はじめに
前回、Go言語のSNMPパッケージgosnmpを紹介しました。
このパッケージの利用を、少し人に、やさしくする方法の説明です。
gosnmpの不便なところ
前回の記事で紹介したサンプルソースコードと実行結果では、MIBの名前を数値のOIDで指定しています。
oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0"}
result, err2 := g.Default.Get(oids) // Get() accepts up to g.MAX_OIDS
や
$go run main.go
0: oid: .1.3.6.1.2.1.1.4.0 string: twsnmp@gmail.com
1: oid: .1.3.6.1.2.1.1.7.0 number: 72
です。
数値のOIDは、人に、やさしくありません。いったい何の情報をSNMPで取得しているのか、すぐには、わからないからです。MIBのオブジェクトには、人が理解しやすいように名前がついています。数値のOIDではなく名前を使ったほうがよいのです。NET-SNMPの場合は、名前でアクセスできます。
$snmpget -v 2c -c public 192.168.1.210 sysContact.0 sysServices.0
SNMPv2-MIB::sysContact.0 = STRING: twsnmp@gmail.com
SNMPv2-MIB::sysServices.0 = INTEGER: 72
SNMPを開発したテネシー大学のケース教授がSNMPセミナーで
ネットワーク管理者が夜中の3時に電話で起こされて、
「.1.3.6.1.2.1.1.7.0の値がオカシイ」
と言われても、何を意味するのか理解できないでしょう。
というジョークで笑いをとっていたのを思い出します。
MIBのOIDと名前を変換するGo言語のパッケージ
名前問題を解決するために数値のOIDと名前を変換するGo言語のパッケージを作りました。
です。
使い方
$go get github.com/twsnmp/go-mibdb
package main
import (
"fmt"
"log"
mibdb "github.com/twsnmp/go-mibdb"
)
func main() {
m, err := mibdb.NewMIBDB("./mib.txt")
if err != nil {
fmt.Printf("NewMIBDB failed err=%v", err)
return
}
fmt.Printf("sysDescr=%s\n", m.NameToOID("sysDescr"))
fmt.Printf(".1.3.6.1.2.1.1.1.0=%s\n", m.OIDToName(".1.3.6.1.2.1.1.1.0"))
}
これを実行すると
$go run main.go
sysDescr=.1.3.6.1.2.1.1.1
.1.3.6.1.2.1.1.1.0=sysDescr.0
のようになります。数値のOIDと名前の変換ができます。
mib.txtの作り方
MIBのOIDの名前の関係はmib.txtというファイルで定義しています。
中身は
.1.3
.iso.org
.1.3.6
.iso.org.dod
.1.3.6.1
.iso.org.dod.internet
.1.3.6.1.1
.iso.org.dod.internet.directory
.1.3.6.1.2
.iso.org.dod.internet.mgmt
.1.3.6.1.2.1
.iso.org.dod.internet.mgmt.mib-2
のようになっています。2行一組で、1行目がOID、2行目が名前です。
からダウンロードできます。
拡張MIBも含めた定義ファイルが必要ならば自分で作成できます。NET-SNMPのsnmptranslateコマンドが必要です。
$snmptranslate -T os > mib.txt
で作成できます。
サンプルプログラムを人に、やさしく書き換える
前回のサンプルプログラムを、このパッケージを使って書き換えてみます。
package main
import (
"fmt"
"log"
g "github.com/gosnmp/gosnmp"
+ mibdb "github.com/twsnmp/go-mibdb"
)
func main() {
+ m, err := mibdb.NewMIBDB("./mib.txt")
+ if err != nil {
+ log.Fatalf("NewMIBDB failed err=%v", err)
+ }
// Default is a pointer to a GoSNMP struct that contains sensible defaults
// eg port 161, community public, etc
g.Default.Target = "192.168.1.210"
// g.Default.Community = "public"
// g.Default.Port = 161
err = g.Default.Connect()
if err != nil {
log.Fatalf("Connect() err: %v", err)
}
defer g.Default.Conn.Close()
- oids := []string{"1.3.6.1.2.1.1.4.0", "1.3.6.1.2.1.1.7.0"}
+ oids := []string{m.NameToOID("sysContact.0"), m.NameToOID("sysServices.0")}
result, err2 := g.Default.Get(oids) // Get() accepts up to g.MAX_OIDS
if err2 != nil {
log.Fatalf("Get() err: %v", err2)
}
for i, variable := range result.Variables {
- fmt.Printf("%d: oid: %s", i, variable.Name)
+ fmt.Printf("%d: oid: %s name:%s = ", i, variable.Name, m.OIDToName(variable.Name))
// the Value of each variable returned by Get() implements
// interface{}. You could do a type switch...
switch variable.Type {
case g.OctetString:
bytes := variable.Value.([]byte)
fmt.Printf("string: %s\n", string(bytes))
default:
// ... or often you're just interested in numeric values.
// ToBigInt() will return the Value as a BigInt, for plugging
// into your calculations.
fmt.Printf("number: %d\n", g.ToBigInt(variable.Value))
}
}
}
実行すると
$go run main.go
0: oid: .1.3.6.1.2.1.1.4.0 name:sysContact.0 = string: twsnmp@gmail.com
1: oid: .1.3.6.1.2.1.1.7.0 name:sysServices.0 = number: 72
のようになります。人にやさしくなったでしょう。
余談
Go言語で開発しているTWSNMPシリーズ
は、最初、このパッケージ使って名前とOIDの変換だけ対応していました。
でも、NET-SNMPは取得したMIB情報の表示をもっと人にやさしい方法でできるのが悔しくて、ASN.1のMIB定義ファイルを読み込んでNET-SNMPと同じように表現できる仕組みを作りました。この話も、いつか書こうと思います。