dullwhaleのメモ帳

何度も同じことを調べなくてよいように...

Cisco機器とexpect(Tcl)スクリプトで自動対話する

Cisco機器とexpectスクリプトで自動対話し必要な情報だけを出力する

ネットワーク機器などのCLIインタラクティブなやり取りを想定して、ワンライナーでは処理が難しいことがある。 ここではexpectスクリプトを用いてCisco機器と自動で対話し、さらに必要な情報だけを出力することを目指す。

expectスクリプトはTclの拡張であるから、スクリプトの書き方に困ったらTclのドキュメントを確認すべし。 ここで「スクリプト」であることに注目せよ。 対話結果をコマンドを組み合わせてワンライナーで処理するより、Tclスクリプト内で処理してしまった方が楽かもしれない。 シェバンをつけておけばファイルにchmodで実行権限をつけて./script.tclのようにするだけで実行できる。

以下のスクリプトDHCPアドレスプールarea1-dhcpからarea9-dhcpのリース中IPアドレスの数を出力する。

#!/usr/bin/expect
# 標準出力へのログを無効化する。putsしたものだけが書かれるようになる。
log_user 0

set now [clock seconds]
set formatted_time [clock format $now -format "%T"]
# いつ時点の結果か分かるように現在時刻を出力しておく
puts $formatted_time

set LOGIN_PASSWORD "password_here"
set ENABLE_PASSWORD "password_here"
set pools {
    area1-dhcp area1-dhcp
    area2-dhcp area2-dhcp
    area3-dhcp area3-dhcp
    area4-dhcp area4-dhcp
    area5-dhcp area5-dhcp
    area6-dhcp area6-dhcp
    area7-dhcp area7-dhcp
    area8-dhcp area8-dhcp
    area9-dhcp area9-dhcp
}
set timeout 5

spawn env LANG=C /usr/bin/ssh CiscoSwitch
expect {
    "Password:" {
        send "${LOGIN_PASSWORD}\n"
    }
}
expect {
    "CiscoSwitch>" {
        send "enable\n"
    }
}
expect {
    "Password:" {
        send "${ENABLE_PASSWORD}\n"
    }
}

    
foreach {_ val} $pools {
    send "show ip dhcp pool $val\n"
    set count 0
    # Leased addresses : の行から数字だけ抜き出して出力する
    expect {
        -re "Leased addresses\[\[:blank:\]\]*:\[\[:blank:\]\]*\[\[:digit:\]\]+" {
            regexp {[[:digit:]]+} $expect_out(0,string) count
        }
    }
    puts $count
}

実行例

./script.tcl
17:28:19
24
34
29
32
31
29
30
34
29

背景

Ciscoの機器からDHCPリースの状況を取得する必要があった。 長期的なものであれば、監視サーバからSNMPで取得するが、今回は期間が短く、使い捨てたい。 機器のコンソールに入ってshow ip dhcp pool ${POOL_NAME}すれば一応の目的は達成できるが、ずっと張り付いている訳にもいかない。 このスクリプトwatchコマンドで定期実行し、出力をファイルに追記していく形にすれば即席の監視ができる。