![見出し画像](https://assets.st-note.com/production/uploads/images/156890775/rectangle_large_type_2_6d5edff4ba94bc65a2b573811d5ce816.png?width=1200)
TWSNMP FC/FKのgNMI対応開発7日目:gNMIツールのPath指定で悩んでいます
浦和レッズ 3連敗!
もやもやしますが、開発に集中して切り替えします。
今朝は、助手の猫さんが4時半にベッドからはみ出した私の足の裏をペロッと舐めて起こしてくれました。おかげで一気に目が覚めました。
昨日作ったgNMIツールのGet機能ですが、とんでもなく間違っていました。最初にテストしたPathは、/system/nameだったので、なんとなくうまく言っているように見えたのですが、Pathに
/interface/statistics
を指定すると、
![](https://assets.st-note.com/img/1728164581-DsBRr96TmOFcpavNoVI2jxbl.png?width=1200)
のようなことになりました。LANポートの情報全部が1つのJSONに入っていて、それだけをテーブルに表示している状態でした。
gNMIcのAPIの使い方を誤解していたようです。取得したJSONデータから自分で情報を取り出す必要がありました。その処理がすっぽり抜けていたのでした。
JSONを解析して情報を取り出す処理を作ることにしました。作ってみると、JSONで配列になっているデータの位置を特定するPathの指定が、さっぱりわかりません。同じPath(情報の名前)で複数あるデータの位置を指定する方法です。"XPATH 配列"で検索して /interfces[0]のような指定でできるのかと試しましたがだめでした。
昨日は諦めてモヤモヤしながら寝ました。今朝、頭がスッキリしたので、いろいろ探して
の資料を見つけました。
どうやら
/interfaces/interface[name=Ethernet/1/2/3]/state
のようにKeyを指定して特定するようです。[name=Ethernet/1/2/3]の部分です。
前に作ったテストプログラムを改造して
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"reflect"
"strings"
"github.com/openconfig/gnmic/pkg/api"
)
type PathValueEnt struct {
Path string
Value string
}
func main() {
// create a target
tg, err := api.NewTarget(
api.Name("srl1"),
api.Address("192.168.1.50:57400"),
api.Username("admin"),
api.Password("NokiaSrl1!"),
api.SkipVerify(true),
)
if err != nil {
log.Fatal(err)
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// create a gNMI client
err = tg.CreateGNMIClient(ctx)
if err != nil {
log.Fatal(err)
}
defer tg.Close()
// create a GetRequest
getReq, err := api.NewGetRequest(
// api.Path("/interface"),
api.Encoding("json_ietf"))
if err != nil {
log.Fatal(err)
}
// fmt.Println(prototext.Format(getReq))
// send the created gNMI GetRequest to the created target
getResp, err := tg.Get(ctx, getReq)
if err != nil {
log.Fatal(err)
}
// fmt.Println(prototext.Format(getResp))
for _, not := range getResp.GetNotification() {
for _, u := range not.GetUpdate() {
pa := []string{}
for _, p := range u.Path.Elem {
pa = append(pa, p.GetName())
}
j := u.Val.GetJsonIetfVal()
var d interface{}
if err := json.Unmarshal(j, &d); err != nil {
log.Fatalln(err)
}
path := ""
if len(pa) > 0 {
path = "/" + strings.Join(pa, "/")
}
for i, r := range getPathValue(d, path, false) {
log.Printf("%d %s = %s", i, r.Path, r.Value)
}
}
}
}
func getPathValue(d interface{}, path string, inArray bool) []PathValueEnt {
r := []PathValueEnt{}
switch v := d.(type) {
case string:
r = append(r, PathValueEnt{
Path: path,
Value: v,
})
return r
case float64:
r = append(r, PathValueEnt{
Path: path,
Value: fmt.Sprintf("%v", v),
})
case bool:
r = append(r, PathValueEnt{
Path: path,
Value: fmt.Sprintf("%v", v),
})
case map[string]interface{}:
n := ""
if in, ok := v["name"]; ok {
if sn, ok := in.(string); ok {
n = sn
}
}
for k, vv := range v {
if inArray && n != "" {
r = append(r, getPathValue(vv, fmt.Sprintf("%s[name=%s]/%s", path, n, k), false)...)
} else {
r = append(r, getPathValue(vv, path+"/"+k, false)...)
}
}
case []interface{}:
for _, vv := range v {
r = append(r, getPathValue(vv, path, true)...)
}
default:
log.Fatalf("%s=%+v type=%v", path, v, reflect.TypeOf(d))
}
return r
}
のように再帰的に取得してPathに[name=xxx]を含めるようにしてみました。かなりうまくいくようです。
実行すると
2024/10/06 07:06:51 1535 /srl_nokia-interfaces:interface[name=mgmt0]/admin-state = enable
2024/10/06 07:06:51 1536 /srl_nokia-interfaces:interface[name=mgmt0]/mtu = 1514
2024/10/06 07:06:51 1537 /srl_nokia-interfaces:interface[name=mgmt0]/ifindex = 1.07795251e+09
2024/10/06 07:06:51 1538 /srl_nokia-interfaces:interface[name=mgmt0]/last-change = 2024-09-25T01:40:55.293Z
のような感じです。配列のキーがnameの場合はOKですが、それ以外には対応していません。indexで位置を指定するもの、キーがないものもありました。取得した時にエラーになる場合は、エラーメッセージでキーの指定の間違いがわかるよにしておきました。
このテストプログラムをTWSNMP FCに反映させて、
![](https://assets.st-note.com/img/1728166281-DLzle6NV094TcuhrUqMwvmxP.png?width=1200)
のように取得できるようになりました。
ほとんどの場合、Pathの列の値をコピペすれば、値を取得できるはずです。
なんとなく画期的な方法じゃないかと思っています。
ポーリングの時は、JQで取得する方法がよいのではと思っています。
明日に続く
いいなと思ったら応援しよう!
![twsnmp](https://assets.st-note.com/production/uploads/images/14333815/profile_ee1accba5615957e5029db85d57fdb0a.jpg?width=600&crop=1:1,smart)