VMware NSXのESGのインターフェースカウンタをInfluxDBとGrafanaで可視化する

> [vExperts Advent Calendar 2016](http://www.adventar.org/calendars/1709)の20日目の記事です。

VMware NSX環境で論理的なルーターとして機能するESG(Edge Service Gateway)は仮想アプライアンスとして動作するが、各ESGはSNMPに対応していないので通常のネットワーク機器のようにSNMP経由でカウンタを取得して外部のツールによって監視することができない。
NSXのESGの各種カウンタはNSX ManagerのREST API経由で取得することが可能なので、スクリプトを使ってInfluxDBにカウンタをレコードとして書き込んでGrafanaで可視化してみる。

- [InfluxDB](https://www.influxdata.com/) : 時系列データの格納に適したデータストア。
- [Grafana](http://grafana.org/) : Graphite/InfluxDB/Elasticsearch/Prometheus/CloudWatch等のをデータソースとして、格納されたデータを可視化するためのソフトウェア。

---

## NSX API

NSX Managerで管理される様々なオブジェクトに対するAPIはNSX Managerによって一元的に提供される。NSXのAPIに関するドキュメントは[ここ](https://www.vmware.com/support/pubs/nsx_pubs.html)。今回は以下のAPIを利用。

- Edge一覧の取得 : ```https://NSX-Manager-IP-Address/api/4.0/edges/```
- 各Edgeのインターフェースカウンタの取得 : ```https://NSX-Manager-IP-Address/api/4.0/edges/[edgeId]/statistics/dashboard/interface?interval=range```

他にもSLBやFW、VPN等に関するカウンタを取得可能。詳細は[API Guide](https://www.vmware.com/support/pubs/nsx_pubs.html)を参照。(※API Guideは一部誤りがあるので注意)

- Load Balancer : ```/api/4.0/edges/[edgeId]/loadbalancer/statistics```
- Firewall : ```/api/4.0/edges/[edgeId]/statistics/dashboard/firewall?interval=range```
- IPSec : ```/api/4.0/edges/[edgeId]/statistics/dashboard/ipsec?interval=range```
- SSL-VPN : ```/api/4.0/edges/[edgeId]/statistics/dashboard/sslpvn?interval=range```
- L2VPN : ```/api/4.0/edges/[edgeId]/l2vpn/config/statistics```

---

### Edgeリストの取得
以下のAPIからNSX Managerが管理するEdgeリストをXML形式で取得することができる。

```REST
GET https://NSX-Manager-IP-Address/api/4.0/edges/
```

- 各EdgeにはNSX Managerが一位のEdge ID(objectId)を割り当てて管理している。(```<objectId>edge-xxx</objectId>```)
- NSX Managerが管理するEdgeには仮想アプライアンスとして機能するESGと、DLR(Distributed Logical Router/分散ルーター)Control VMの二種類があり、EdgeTypeタグで分類されている。DLRはハイパーバイザー内で機能するため今回は```gatewayServices```のみを対象としてインターフェースカウンタを取得する。

 - Edge Service Gateway = ```<edgeType>gatewayServices</edgeType>```
 - DLR Control VM = ```<edgeType>distributedRouter</edgeType>```

---

#### EdgeリストのXMLレスポンスの一部
各Edgeは```<edgeSummary></edgeSummary>```要素として確認できる。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<pagedEdgeList>
  <edgePage>
    <pagingInfo>
      <pageSize>256</pageSize>
      <startIndex>0</startIndex>
      <totalCount>3</totalCount>
      <sortOrderAscending>true</sortOrderAscending>
      <sortBy>id</sortBy>
    </pagingInfo>
    <edgeSummary>
      <objectId>edge-1</objectId>
      <objectTypeName>Edge</objectTypeName>
      <vsmUuid>422CC825-5AC5-EEE6-E4DE-2FDF7F2AF278</vsmUuid>
      <nodeId>3a86d15e-a821-4221-88a4-15225c6c965e</nodeId>
      <revision>78</revision>
      <type>
        <typeName>Edge</typeName>
      </type>
      <name>ESG-VLA159</name>
      <clientHandle/>
      <extendedAttributes/>
      <isUniversal>false</isUniversal>
      <universalRevision>0</universalRevision>
      <id>edge-1</id>
      <state>deployed</state>
      <edgeType>gatewayServices</edgeType>
      <datacenterMoid>datacenter-2</datacenterMoid>
      <datacenterName>DC</datacenterName>
      <tenantId>default</tenantId>
      <apiVersion>4.0</apiVersion>
      <recentJobInfo>
        ...
      </recentJobInfo>
      <edgeStatus>GREEN</edgeStatus>
      <numberOfConnectedVnics>5</numberOfConnectedVnics>
      <appliancesSummary>
        ...
      </appliancesSummary>
      <hypervisorAssist>false</hypervisorAssist>
      <allowedActions>
        ...
      </allowedActions>
    </edgeSummary>
    <edgeSummary>
      <objectId>edge-224</objectId>
      ...
    </edgeSummary>
  </edgePage>
</pagedEdgeList>
```

---

### Edgeのインターフェースカウンタの取得

各Edgeのインターフェースカウンタは以下のリクエストで取得可能。

```REST
GET https://NSX-Manager-IP-Address/api/4.0/edges/[edgeId]/statistics/dashboard/interface?interval=range
```

- ```[edgeId]```にはインターフェースカウンタを取得する対象のEdgeのobjectIdを指定する。
- レスポンスボディのXMLはmeta要素と、data要素で構成され、各インターフェースに関して入力パケット数、入力バイト数、出力パケット数、出力バイト数が含まれる。(なお、カウンタ名がinbytes/outbytesとなっているが、実際のトラフィックを確認すると、どうやらkbpsが正しい単位の模様。)

---

#### EdgeのインターフェースカウンタのXMLレスポンス

data要素に各インターフェースのinpkt/outpkt/inbytes/outbytesデータが入っている。

```xml
<?xml version="1.0" encoding="UTF-8"?>
<dashboardStatistics>
    <meta>
        <startTime>1480911320</startTime>
        <endTime>1480911360</endTime>
        <interval>20</interval>
        <vnics>
            <vnic>
                <name>vnic0</name>
                <index>0</index>
            </vnic>
            <vnic>
            ...
            </vnic>
        </vnics>
    </meta>
    <data>
    <interfaces>
            <vNic__0__in__pkt>
                <dashboardStatistic>
                    <timestamp>1480911320</timestamp>
                    <value>24.19482774794</value>
                </dashboardStatistic>
                <dashboardStatistic>
                    <timestamp>1480911340</timestamp>
                    <value>46.188073834689995</value>
                </dashboardStatistic>
            </vNic__0__in__pkt>
            <vNic__0__in__byte>
                <dashboardStatistic>
                    <timestamp>1480911320</timestamp>
                    <value>23.480170347359998</value>
                </dashboardStatistic>
                <dashboardStatistic>
                    <timestamp>1480911340</timestamp>
                    <value>65.00158679382001</value>
                </dashboardStatistic>
            </vNic__0__in__byte>
            <vNic__0__out__pkt>
                <dashboardStatistic>
                    <timestamp>1480911320</timestamp>
                    <value>17.026659284</value>
                </dashboardStatistic>
                <dashboardStatistic>
                    <timestamp>1480911340</timestamp>
                    <value>37.182411631</value>
                </dashboardStatistic>
            </vNic__0__out__pkt>
            <vNic__0__out__byte>
                <dashboardStatistic>
                    <timestamp>1480911320</timestamp>
                    <value>28.310770795</value>
                </dashboardStatistic>
                <dashboardStatistic>
                    <timestamp>1480911340</timestamp>
                    <value>72.218770663</value>
                </dashboardStatistic>
            </vNic__0__out__byte>
            <vNic__1__in__pkt>
                ....
            </vNic__0__in__pkt>
            ....
        </interfaces>
    </data>
</dashboardStatistics>
```

---

## InfluxDBとGrafanaのセットアップ

### dockerで簡単にセットアップ

```bash
docker run -itd -p 3000:3000 --name grafana grafana/grafana
docker run -itd -p 8083:8083 -p 8086:8086 -e INFLUXDB_ADMIN_ENABLED=true -v $PWD:/var/lib/influxdb influxdb
```

InfluxDB 1.1から管理用インターフェース(Port 8083)はデフォルトで利用できなくなっているので注意。

環境変数```INFLUXDB_ADMIN_ENABLED=true```を指定しないと、InfluxDBの管理画面を表示することができない。(https://docs.influxdata.com/influxdb/v1.1/administration/config/#enabled-false)

---

### InfluxDBのデータベース作成

InfluxDBのAPIからESGのカウンタを格納するためのデータベース(nsx_db)を作成する。

```bash
curl -X POST http://localhost:8086/query?q=create+database+%22nsx_db%22
```

---


## Edgeリストを取得し、各ESGのインターフェースカウンタをInfluxDBへ格納

以下のPythonのスクリプトを作成して、NSX APIから取得したESGのインターフェースカウンタを、InfluxDB上のデータベースに対して、NSX Manager毎にmeasurementを指定、ESGの```objectId```とインターフェース名をTagとして、[influxdb-python](https://github.com/influxdata/influxdb-python)によりInfluxDBのレコードとして追加。

- [get_edge_ifstats.py](https://gist.github.com/masanara/ef041c00710f1a271f435c2bc44ac8f1)

これをcronで5分毎に実行して、InfluxDBにレコードを追加。

---

### InfluxDBに追加するデータのフォーマット

実際にレコードを追加する際のデータは以下のような形。

```json
[
  {
    "fields": {
      "inbyte": 71.46487064655,
      "inpkt": 50.95460165519,
      "outbyte": 82.579703146,
      "outpkt": 43.43723174
    },
    "tags": {
      "vnic": "vNic0",
      "edge_id": "edge-1"
    },
    "time": "2016-12-14T11:30:40+00:00",
    "measurement": "10.44.59.208"
  },
  {
    "fields": {
      "inbyte": 91.3446508269,
      "inpkt": 68.23450442,
      "outbyte": 74.1757490272,
      "outpkt": 67.2185983652
    },
    "tags": {
      "vnic": "vNic1",
      "edge_id": "edge-1"
    },
    "time": "2016-12-14T11:30:40+00:00",
    "measurement": "10.44.59.208"
  },
  …
]
```

---

### InfluxDBに追加されたレコードの確認

管理画面のQueryを使ってレコードが追加されたかどうかを確認することができる。

#### measurementの確認

```show measurements```により、NSX Manager毎にmeasurementが作成されたことを確認できる。

![Kobito.laxM98.png](https://qiita-image-store.s3.amazonaws.com/0/27668/098dc514-0d6f-12c5-a904-6a67ee4a7bb9.png "Kobito.laxM98.png")

---

#### レコードの確認

```select * from "10.44.59.208" where edge_id='edge-1'```により、measurement内のレコードを確認できる。各レコードは、ESGの```objectId```やESGの```vnic```をタグとして、APIから取得したカウンタを格納している。

![Kobito.rPJu5C.png](https://qiita-image-store.s3.amazonaws.com/0/27668/5d65e302-5076-4751-eb7d-57b7f276180e.png "Kobito.rPJu5C.png")

---

## Grafanaによる可視化

### Deta Sourceの登録
GrafanaがInfluxDBのレコードを参照できるように、Data Sourceを登録する。

![Kobito.GtDJQa.png](https://qiita-image-store.s3.amazonaws.com/0/27668/07e6e428-014c-700b-d313-cb359eb2593c.png "Kobito.GtDJQa.png")

---

### Templating

ESGには10個のvnicがついていこれを一つ一つグラフを作るのは大変なので、GrafanaのTemplatingとRepeat Graph機能を使ってグラフを作成する。

DashboardのTemplatingで、NSX Managerの一覧(```$nsxmgr```)、ESGの一覧(```$edges```)、vnicの一覧(```$vnic```)を動的な変数として定義する。

![Kobito.y9PzvY.png](https://qiita-image-store.s3.amazonaws.com/0/27668/af29a93d-b24e-9665-849b-a3405f3bea4f.png "Kobito.y9PzvY.png")


---

### Graphの作成

メトリックとして、Templatingで定義した変数に関する、inbyte/outbyteをプロットする。

![Kobito.KBeFKG.png](https://qiita-image-store.s3.amazonaws.com/0/27668/be56360b-752d-1c52-0298-1639ebb0e1c0.png "Kobito.KBeFKG.png")

---

Repeat Panelとして、vnicを指定して、Templatingで選択可能にした変数の内、```$vnic```に関してパネルを繰り返すよう指定する。

![Kobito.ahRvO1.png](https://qiita-image-store.s3.amazonaws.com/0/27668/0c15eea9-c3ff-0cb4-3fc2-786fac248ce8.png "Kobito.ahRvO1.png")

---

### Graphの表示

Templating機能を使うとこんな感じで、インタラクティブなグラフを表示することができ、Repeat Panelで各ESGの全てのインターフェースのカウンタをまとめて表示することができる。

![grafana.gif](https://qiita-image-store.s3.amazonaws.com/0/27668/1d87a7a3-7b8c-b619-de57-19f69dff0328.gif "grafana.gif")








nsnnnnnn