新しくなったsnmp-exporterのgeneratorの使い方

# snmp-exporterとは
Prometheusから、SNMP経由での情報をモニタリングする際に利用するExporterです。
機能は単純で、リクエストが来るとSNMPを利用して情報を集めて値を返すだけです。

[SNMP Exporter](https://github.com/prometheus/snmp_exporter)

# SNMP Exporterの設定
SNMP Exporterの設定は、SNMPを利用してどこのOIDからデータを拾ってくるかをymlファイルに記述して設定します。
このファイルは非常に複雑なため、手作業での作成や修正は非推奨となっており後述するgeneratorを利用して生成するのが一般的になっています。

generatorを使用するには`generator.yml`ファイルに収集する場所やオプションを記述して、
そのファイルをもとにgeneratorを実行することで設定ファイル(snmp.yml)が生成されます。

# SNMP Exporterの破壊的変更

このgeneratorですが、snmp-exporterの[バージョン 0.23.0](https://github.com/prometheus/snmp_exporter/releases/tag/v0.23.0)で破壊的変更が行われており、
それまで以前のv0.22.0以下の`generator.yml`ファイルはビルドできなくなっています。

詳しい変更内容を見たい方は右から差分を確認してください⇒[当該コミット](https://github.com/prometheus/snmp_exporter/commit/5e9971612370900e0c1a26068aa8cd019e891b56)

この破壊的変更では、構成ファイルがモジュールごとのフラットな単位のリストからメトリクスのウォーキングおよびマッピングモジュールと認証の構成に分割されました。

そのため以前のフォーマットの`generator.yml`を使用してビルドしようとすると以下のようなエラーが出ます

```bash
docker run -ti -v "/home/owner/metrics-dev/snmp_exporter/generator:/opt/" "prom/snmp-generator:main" generate
ts=2023-10-17T08:43:48.526Z caller=net_snmp.go:162 level=info msg="Loading MIBs" from=mibs
ts=2023-10-17T08:43:48.843Z caller=main.go:132 level=error msg="Error generating config netsnmp" err="error parsing yml config: yaml: unmarshal errors:\n  line 17: field version not found in type main.plain\n  line 21: field auth not found in type main.plain\n  line 45: field version not found in type main.plain\n  line 49: field auth not found in type main.plain"
make: *** [Makefile:86: docker-generate] Error 1
```

私もこのエラーに遭遇した際は調べても原因がなかなか見つからず、解決策に行き着くまで時間を要しました。
原因は以前のフォーマットの設定ファイルでは新しいフォーマットとの互換性がないためです。

そのためバージョン0.22以前に作成した`generator.yml`は新しい構成に合わせて作り直す必要があります。

まずバージョン0.22以下での`generator.yml`の例を示します

```yml:generator.yml
modules:
  yamaha_rt_v3: # SNMPv3でのサンプル
    walk:
      - 1.3.6.1.4.1.1182.2.1.4 # yrhMemoryUtil
    lookups:
      - source_indexes: [ifIndex]
        lookup: ifAlias
    overrides:
      ifAlias:
        ignore: true # Lookup metric
      ifDescr:
        ignore: true # Lookup metric
      ifName:
        ignore: true # Lookup metric
      ifType:
        type: EnumAsInfo
    version: 3
    max_repetitions: 25
    retries: 3
    timeout: 10s
    auth:
      username: (ユーザー名)
      security_level: authPriv
      password: (認証パスワード)
      auth_protocol: SHA
      priv_protocol: AES
      priv_password: (暗号パスワード)
      context_name: rtx-snmp.jp

  yamaha_rt_v2c: # SNMPv2cでのサンプル
    walk:
      - 1.3.6.1.4.1.1182.2.1.4 # yrhMemoryUtil
    lookups:
      - source_indexes: [ifIndex]
        lookup: ifAlias
    overrides:
      ifAlias:
        ignore: true # Lookup metric
      ifDescr:
        ignore: true # Lookup metric
      ifName:
        ignore: true # Lookup metric
      ifType:
        type: EnumAsInfo
    version: 2
    max_repetitions: 25
    retries: 3
    timeout: 10s
    auth:
      community: public # SNMPコミュニティ名
```

以前のバージョンではmodulesの中に情報を収集する機器別にモジュールを定義して、
そのモジュール内にSNMPのバージョンであったり認証情報を適宜記載する方式となっていました。

この方式では同じ認証情報を使いまわすSNMPエージェントがあった場合は同じ設定を
複数のモジュールに記述しなくてはならず非効率です。

そのため新しい方式では認証情報もモジュール化して認証情報を使いまわせるようになっています。

以下に新しい方式での`generator.yml`のフォーマットを示します

```yml:generator.yml
auths:
  yamaha_rt_v3_auth: # v3用の認証情報
    version: 3
    username: (ユーザー名)
    security_level: authPriv
    password: (認証パスワード)
    auth_protocol: SHA
    priv_protocol: AES
    priv_password: (暗号パスワード)
    context_name: rtx-snmp.jp
  yamaha_rt_v2_auth: # v2用の認証情報
    version: 2
    community: public # SNMPコミュニティ名

modules:
  yamaha_rt_v3: # SNMPv3でのサンプル
    walk:
      - 1.3.6.1.4.1.1182.2.1.4 # yrhMemoryUtil
    lookups:
      - source_indexes: [ifIndex]
        lookup: ifAlias
    overrides:
      ifAlias:
        ignore: true # Lookup metric
      ifDescr:
        ignore: true # Lookup metric
      ifName:
        ignore: true # Lookup metric
      ifType:
        type: EnumAsInfo
    max_repetitions: 25
    retries: 3
    timeout: 10s
yamaha_rt_v2c: # SNMPv2cでのサンプル
    walk:
      - 1.3.6.1.4.1.1182.2.1.4 # yrhMemoryUtil
    lookups:
      - source_indexes: [ifIndex]
        lookup: ifAlias
    overrides:
      ifAlias:
        ignore: true # Lookup metric
      ifDescr:
        ignore: true # Lookup metric
      ifName:
        ignore: true # Lookup metric
      ifType:
        type: EnumAsInfo
    max_repetitions: 25
    retries: 3
    timeout: 10s
```

大きな違いとしては各モジュールからはSNMPのバージョン指定や認証情報の
項目が消えており、authsの中に認証情報が分割されています。

実際の認証情報の指定はデータを収集するPrometheus側の設定ファイル`prometheus.yml`で設定します

```yml:prometheus.yml
scrape_configs:
  - job_name: 'snmp'
    static_configs:
      - targets:
        - 192.168.10.100
    metrics_path: /snmp
    params:
      auth: [yamaha_rt_v3_auth]
      module: [yamaha_rt_v3]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: 127.0.0.1:9116
```

paramsのauthに使用する認証モデルを指定します。
このように書けると同じ認証を複数の機器に使いまわすことができて便利です。