動的プラグインは、ノードの健全性を確認するために、サポートされているトランスポート ノード(ESXi ホストなど)に作成できるカスタマイズされたプラグインです。

動的プラグインはランタイムにインストールできます。次の機能を実行します。

  • 影響を受けるトランスポート ノードをシステム ログに記録します。
  • run_command() 機能を使用して、コマンドまたは CLI を実行します。
  • 既存のメトリックを読み取ります。
  • wavefront にデータをエクスポートします(VMware Cloud 環境のみ)。

NSX の管理に関する専門知識があれば、動的プラグインを作成できます。動的プラグインは、VMware のサポートを利用して作成することもできます。作成したプラグインは、検証のため、GIT リポジトリに送信する必要があります。プラグインの送信前に確認とテストを行う必要があります。

セキュリティ管理

プラグインの確認とテストが完了したら、検証のため、プラグイン、テスト結果、コードの変更を GIT リポジトリに送信します。次の GIT リポジトリの詳細を使用します

  • GitLab: https://gitlab.eng.vmware.com/core-build/nsbu-sha-plugin
  • 製品:nsx-sha-plugins
  • Gitreview のサポート:VMware チームが実施

プラグインが検証され、承認されると、GIT リポジトリにコミットされます。新しいビルドが作成されると、すべての動的プラグインがビルドされ、署名されます。各プラグインは、個別にパッケージ化されて署名されます。必要なプラグインは、ビルドの公開ファイルから取得できます。

署名済みのプラグインが管理プレーンにアップロードされると、管理プレーンはパブリック キーで署名を検証し、このプラグインが有効であることを確認します。プラグインが検証されると、プラグインのファイルが管理プレーンと中央制御プレーン (CCP) 間、CCP とホスト間のセキュアなチャネルを介して宛先のホストにプッシュされます。

システムの健全性エージェント (SHA) インスタンスが再起動されると、プラグイン ファイルが管理プレーンから再度取得されます。すべてのファイルはセキュアなチャネルを介して公開されているため、一時ファイルは使用されません。これにより、ハッカーによってスクリプトが改ざんされるリスクを回避できます。

また、有害なコードによるリスクを回避するため、SHA はスクリプトの実行前に RestrictedPython を使用して、プラグインの Python スクリプトをチェックします。

バージョン管理

プラグインで使用されているコマンドまたはツールが NSX の新しいバージョンでサポートされていない場合があります。このため、カスタム プラグインでは、サポートされている NSX のバージョンを manifest.yml ファイルに定義する必要があります。サポートされているバージョンをすべて定義するため、バージョンは正規表現で記述する必要があります。ホスト側の SHA がカスタム プラグインのバージョンをチェックし、正規表現で一致したバージョンだけを実行します。

推奨のバージョン管理ポリシーは次のとおりです。
  • サポートされるバージョンとして、メジャー リリースの NSX バージョンを定義します。

    同じメジャー リリースのマイナー リリース間では、コマンドとツールはほとんど変わらないため、次のように、すべてのマイナー リリースのバージョンを定義することをおすすめします。

    次はその例です。

    version: ^2\.5\.[0-9.]+ <== The custom plugin supporting all NSX 2.5 releases

  • 新しいメジャー リリースが公開された場合、送信されたすべての動的プラグインを確認する必要があります。
  • 関連するコマンドまたはツールが変更された場合、プラグインの作成者はスクリプトを更新する必要があります。

動的プラグインのインストール

プラグインをインストールするトランスポート ノードまたは Edge ノードには、30 MB 以上のメモリ領域が必要です。また、インストールできるプラグインは最大 10 個までです。プラグインの数が 10 個を超えると、プラグインのインストールは失敗します。

プラグインをインストールするには、次のタスクを実行します。
  1. GIT リポジトリに動的プラグイン ファイルを作成します。プラグイン ファイルの詳細については、「動的プラグイン ファイル」を参照してください。
  2. GIT リポジトリで製品のビルドをトリガし、動的プラグイン ファイルの ZIP パッケージを生成して、パッケージをダウンロードします。
  3. POST メソッドを含む次の API を使用して、動的プラグインを作成します。

    https://<manager_ip>/api/v1/systemhealth/plugins

  4. POST メソッドを含む次の API を使用して、管理プレーンにプラグインの ZIP パッケージをアップロードします。管理プレーンで、アップロードしたファイルが展開され、必要な検証が行われます。

    /systemhealth/plugins/<plugin-id>/files/<file-name>/data

    注: プラグインの ZIP ファイルの最大サイズは 500K です。
  5. POST メソッドを含む次の API を使用して、必要なトランスポート ノードをメンバーとするノード グループを作成します。

    /<manager_ip>/api/v1/ns-groups

  6. 次の API を使用して新しいサービス構成を作成し、プラグイン プロファイルをノード グループに適用します。サービス構成フレームワークがプラグイン コンテンツをノード グループに送信します。

    https://<manager_ip>/api/v1/service-configs

API の詳細については、『NSX API ガイド』を参照してください。

プラグインの状態の取得

動的プラグインを実行すると、既存のメッセージ チャネルを介して状態情報が管理プレーンに自動的にアップロードされます。管理プレーンは、プラグインの状態情報を集約してデータベースに格納します。各ノードのすべてのプラグインの状態を取得するには、GET メソッドを含む次の API を使用します。

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
プラグインを削除する DELETE /systemhealth/plugins/<plugin-id>
システムの健全性プロファイルを作成する POST /systemhealth/profiles

プラグインの状態を監視する

GET /systemhealth/plugins/status/<node-id>
プラグインを有効にする プラグインを有効にするには、次の 2 段階のプロセスがあります。
  1. 次の API を使用して、enabled プロパティを true または false に設定します。

    https://<manager_ip>/api/v1/systemhealth/profiles/

  2. 次の API を使用して、SHA プロファイルを NS グループに適用します。

    https://<manager_ip>/api/v1/service-configs

プラグインの間隔を変更する POST

プラグインの間隔を変更するには、次の 2 段階のプロセスがあります。

  1. 次の API を使用して、config プロパティを設定します。

    https://<manager_ip>/api/v1/systemhealth/profiles/

  2. 次の API を使用して、SHA プロファイルを NS グループに適用します。

    https://<manager_ip>/api/v1/service-configs

動的プラグイン ファイル

動的プラグインは、次のファイルで構成されています。

  • インストール仕様ファイル。
    インストール仕様ファイル ( 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

    バージョン このプラグインをインストールできる 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 (VMC) 環境にのみ表示されます。
    オプション precondition: ['wavefront']
    次の組み込みモジュールは使用しないでください。
    • os

    • subprocess

    • sys

    • multiprocessing

    • importlib

    次の表に、各モジュールの組み込み機能の代わりに使用する必要があるインターフェイスを示します。これらのインターフェイスはシステムから提供されます。これらは、 manifest.yml にファイルにモジュール/クラスを指定せず、直接使用することもできます。
    モジュール 組み込み機能 代替インターフェイス
    datetime datetime.date.strftime(self, fmt)

    datetime_date_strftime(dt, fmt)

    :param dt: date instance

    :param fmt: format string

    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
    manifest.yml ファイルのサンプル。
    # 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 プロファイルを作成し、管理プレーンから CCP、CCP から NestDB のチャネルを使用して、NS グループ経由でトランスポート ノードに適用します。

    次の表に、 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)は、プラグイン スクリプトで直接使用できます。

    次のサンプル出力のように、出力ログでは、プラグイン名と ID がプレフィックスとして追加されます。

    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

    システム提供のデータを取得するために使用される既存のシステム定義のディクショナリ。たとえば、プロファイル、メトリック、host_id などです。

    変数 profile = data_store['profile']
    profile

    プロファイル データは、data_store から読み取られるデフォルトのプロファイル (plugin.cfg.ym) または有効な 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 にする必要があります。

    2 つ目のキーは既存のメトリック名です。

    データ

    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:コマンドの結果を待機するタイムアウト。デフォルトのタイムアウトは 4s です。20s よりも大きい値は設定できません。

    この関数は、コマンドの実行結果を返します。

    関数

    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 (VMC) 環境にのみ適用されます。
    次の形式になっています。

    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()