TWSNMPのMIBツリー表示
TWSNMPのMIBブラウザーにMIBツリーを表示して、取得する監視データを選ぶ機能を追加した時の話です。あとMIBツリーとは何かも少しだけ書いておきます。日曜の昼に書き始めましたが、続きを書くようにと猫に今朝4時に起こされました。猫はいつのものように、甘えた後ご飯食べて寝ています。
SNMPのMIBがツリー状なのはなぜか?
SNMPを利用してネットワーク監視を行うと、MIBツリーという言葉がでてきます。MIBは「Management information base」というネットワーク管理のための管理情報のデータベースです。SNMPで監視する場合、監視対象のパソコンやルータなどからシステムの名前やLANポートの状態などを取得します。取得した情報を基に監視対象の状態を判断します。この時どの監視対象に聞いても同じ情報を返してもらえる必要があるため、情報にみんなが共通に識別できる名前をつけています。
システムの名前なら
.1.3.6.1.2.1.1.5
.iso.org.dod.internet.mgmt.mib-2.system.sysName
システムが起動してからの経過時間なら
.1.3.6.1.2.1.1.3
.iso.org.dod.internet.mgmt.mib-2.system.sysUpTime
のように定義されています。上の数値の列は、コンピュータが利用するための定義です。これだと人間には不便なので、下の文字列が人間のための名前です。isoが1、orgが3のように対応しています。
この名前は、沢山の管理情報を定義しても重複しないように階層的な管理をして定義しています。最初のisoが国際標準化機構、orgがその中の組織、dodがアメリカの国防総省、internetはインターネットの標準化組織、mgmtが管理機能を考える文化会のような階層です。上の階層が下の階層を定義したら、その下の階層の管理は任せるというイメージです。標準以外の場合は、
.1.3.6.1.4.1.8072.1.1
.iso.org.dod.internet.private.enterprises.netSnmp.netSnmpObjects.nsVersion
のように、インターネットの下にprivate(個別)-enterprises(企業)の下に企業番号を取得すれば、その下の階層に自由にMIBを定義することができます。
MIBは、このように階層的に定義されているので、絵にすると
のようにツリー状になります。
MIBツリーの表示方法
オリジナルのTWSNMPマネージャではWindowsのフォルダ階層を表示するツリービューを利用してMIBツリーの表示を実現していました。
のような感じです。
復刻版では、同じようなものを作るのが大変そうだったので、後回しにしていましがTWSNMPで使用しているグラフ表示のライブラリで、
のサンプルを見つけてMIBツリーを作ってみる気になりました。
MIBツリーのデータ構造を考える
サンプルのソースコードを見るとツリーを表示するためのデータの構造は、
var data = {
"name": "flare",
"children": [
{
"name": "data",
"children": [
{
"name": "converters",
"children": [
{"name": "Converters", "value": 721},
{"name": "DelimitedTextConverter", "value": 4294}
]
},
{
"name": "DataUtil",
"value": 3322
}
]
},
{
"name": "display",
"children": [
{"name": "DirtySprite", "value": 8833},
{"name": "LineSprite", "value": 1732},
{"name": "RectSprite", "value": 3623}
]
},
つづく
のようになっています。基本は、nameとvalueというデータをもつオブジェクトで下の階層がある場合は、同じ構造のデータをchildrenの中に配列で入れればよいことがわかります。
MIBツリーのデータを作る
TWSNMPでは、MIBデータを自作の
というパッケージを使って読み込んでいます。このパッケージで読み込んだデータを使って先程のMIBツリーのデータを作れば表示できるはずです。
// MIBツリーのデータ構造
type mibTreeEnt struct {
name string
oid string
children []*mibTreeEnt
}
// MIBツリーのデータ
var (
mibTree = map[string]*mibTreeEnt{}
mibTreeRoot *mibTreeEnt
)
// ツリーを追加する関数
func addToMibTree(oid, name, poid string) {
n := &mibTreeEnt{name: name, oid: oid, children: []*mibTreeEnt{}}
if poid == "" {
mibTreeRoot = n
} else {
p, ok := mibTree[poid]
if !ok {
astiLogger.Errorf("addToMibTree parentId=%v: not found", poid)
return
}
p.children = append(p.children, n)
}
mibTree[oid] = n
}
// MIBツリーのデータをJSONで返す関数
func makeMibTreeJSON() string {
// 読み込んでいるMIBからOIDのリストを作成する
oids := []string{}
for _, n := range mib.GetNameList() {
oid := mib.NameToOID(n)
if oid == ".0.0" {
continue
}
oids = append(oids, oid)
}
// OIDのリストを順番に並べ替える
sort.Slice(oids, func(i, j int) bool {
a := strings.Split(oids[i], ".")
b := strings.Split(oids[j], ".")
for k := 0; k < len(a) && k < len(b); k++ {
l, _ := strconv.Atoi(a[k])
m, _ := strconv.Atoi(b[k])
if l == m {
continue
}
if l < m {
return true
}
return false
}
return len(a) < len(b)
})
// MIBツリーのデータを作る
addToMibTree(".1.3.6.1", "iso.org.dod.internet", "")
for _, oid := range oids {
name := mib.OIDToName(oid)
if name == "" {
continue
}
lastDot := strings.LastIndex(oid, ".")
if lastDot < 0 {
continue
}
// 親のOIDを作る
poid := oid[:lastDot]
addToMibTree(oid, name, poid)
}
if mibTreeRoot == nil {
//ツリーのルートがなければ空欄を返す
return ""
}
//最後にツリーをJSONの文字列にする
return "{\n" + strings.Join(mibTreeJSONEnt(mibTreeRoot, ""), "\n") + "}\n"
}
ポイントは、数値の名前(OID)順に並べ替えることです。並べ替えは、追加する時に親が見つからないことを防ぐためにツリーの親要素が先になるようにします。最初、並べ替えを文字列の比較でおこなったので表示の順番が毎回変わるようなおかしなことが起こって悩まされました。並べ替えを数値で行うようにしたらうまくいきました。
アメリカ国防総省が出てくる理由
おまけの情報ですが、MIBツリーにはdod=アメリカ国防総省が出てきます。
インターネットが空気のように自然に存在している現在では理由を知る人は少なくなっていると思います。インターネットは、もともとアメリカの軍事的な研究から始まったことに由来しています。
開発のための諸経費(機材、Appleの開発者、サーバー運用)に利用します。 ソフトウェアのマニュアルをnoteの記事で提供しています。 サポートによりnoteの運営にも貢献できるのでよろしくお願います。