CLIベースのNW自動化バッドノウハウのあれこれ(補足)

CLIベースのNW自動化バッドノウハウのあれこれ について、思いの外反響があったのでみんな似たようなところで苦労してるんだろうなーと勝手に思っています。で、実際いろいろ作ってたときの記録などなどを元に少しバッドノウハウ系の話をさらってみました。やっていたもの自体は会社でのあれこれの話とかも入って出せないのですが。もう 5 年以上前の話になるので、最近の環境ではそんなに当てはまらない話があるかもしれませんが、もともと、かつてこういうところで困ったから今どういう動きがあるのか、というのを見てもらえればいいやと思っているので問題ないでしょう。

とつぶやいてみたりしたらいくつかリプライもらったのでその辺も含めてまとめておきます。

ログイン/ログアウト処理関連

ssh strictHostKeyChecking

  • expect で ssh セッションを張る場合、始めてアクセスするホストの鍵確認応答でこけるというのはみんなやったことがあるのでは…。
  • まあテスト時とかはともかく、認証周りの運用とかはまじめに考えないとだめです。
ssh -o strictHostKeyChecking=no

ログインリトライ

  • ログイン処理のリトライ(ユーザ名あるいはパスワードが正しくないときに、数回ログインを繰り返す)処理を入れるかどうか。
    • 1回でうまくログインできないケースがあったんだと思われるけど状況詳細不明です。
    • ちゃんとリトライカウント入れておかないとループします…

ログイン後の強制プロンプト出力のためのリターン入力

  • やりますよね。コマンドのエントリポイントが返ってこないと先に進まないんですよ…。
  • シリアルコンソールサーバを使って、工場出荷状態の機材に管理用の IP を振るところから自動化するというのをやったことがあるんですが、リモートログイン時とシリアル利用時にプロンプトの出方が違うというのもあります。
    • あと、初期状態だと初期設定ウィザードとかに入る機材がそれなりにあるので、そこをキャンセルした上で設定コマンド流し込むとか作ってた。

環境変数

  • ちょっとまえの F5 は、環境変数 TERM の値を見て、知らないやつだとエラー返すというのがありました…(v9だったか?)。テスト用に Cygwin 上でスクリプト書いて実行したら TERM=cygwin だとエラー出されるので環境変数設定し直してるコードが出てきた。
  • F5 さんはこの辺いろいろ変わったという話もあり…最近のは触ったことないんですがどうでしょうね。

ログアウト処理

  • save, exit, logout 等の処理を行う際に yes/no のような確認応答をする必要があるというのは前回にも書いたとおり。
  • 問題は、ログインしたい時点で、CLI上、どのモードになってるかなんですよね。たとえば Cisco の機材で、いくつかコマンドをなげていて、特権モードで interface 設定していた状態 Router(config-if)# だったとしたら、いったんそのモードを抜けてからログアウトコマンドを打たないとちゃんとログアウトしてくれないわけです。いくつか対応策はあります。たとえばこんな感じ。
    • 投げ込むコマンドを記述する段階でログアウトまで意識したコマンドを記述しておく。
      • コード書く処理としては簡単ですが、コマンドシーケンス作る段階で間違えて exit 多いと処理中断したり少ないとうまくログアウトしなかったり、チェックが難しいです。
configure terminal
interface gi0/1
 ip addr...
 no shut
 exit           <= config-if 抜ける
exit            <= config 抜ける
exit            <= enable 抜ける
exit            <= ログアウト
    • セッションが切れるまで exit を繰り返し送るといった処理にしておく
      • モード抜けて、最終的にログアウトする段階で yes/no が入ったりするのでそこがどうなるか。
  • モード遷移とかも管理するのかとかね…。
    • エラー有無を無視して end, exit, exit をまとめて流すようにしておくとかもあるかもしれない。

コマンド処理

文字列処理のあれこれ

  • 前も書きましたが、パラメタ化すると ASCII 文字以外を書いてくる人がいます。
  • パラメタの埋め込み
    • テンプレートエンジンとか使ったりするわけですが…。パラメタのバリデーション*1 や、パラメタ指定があったりなかったりするケース*2 をどう扱うかは考えておく必要があります。
    • バリデーションも…省略記法が許されるモノとかがあると非常に怪しげに。

  • description や remark とかにいろいろ tag 的な情報埋め込んでるところも見たことがあるので…

コマンド別エラー処理

  • show コマンドなどの出力にプロンプト相当の文字列が含まれるケース…みたいな話を前回したんですが、show log とかやったら、コマンド入力時に引っかけることにしていたエラーメッセージ (たとえば "Command Not Found" みたいなメッセージ) がそのまま出てきて引っかかって処理中断とかね…
    • 仕方がないので、このコマンドに対しては、次のプロンプトが出るまでエラーは無視する、といった処理いれるわけです。

ループ回避

  • これは処理系依存の話があるかもしれないですが…。perl-Expect だと、イベントに対してコールバックを設定しておく形になるのでそれを想定してください。
    • spawn したプロセスから返ってくる応答(文字列)について正規表現マッチして、マッチした正規表現に対して設定されているコールバックを呼ぶ。正規表現は複数登録できて、上から順にチェックしていく…という動作をします。
  • 上記の、あるコマンドに対するエラー無視とか、何かを無視して先に進むようなケースはリスクがあります。
    • たとえば、コマンド出力にプロンプト相当の文字列があるので無視して先に進む、みたいなのを考えるとわかりやすいと思います。下手すると無限にプロンプト待ちになります。
    • 特権モード移行も、多くのネットワーク機器は特権モードになるとプロンプトが変わるんですが、あるデバイスでは、特権ユーザではいると最初から特権モード状態だったりして、特権モードコマンドの前後でプロンプトが変化しないことがあります。で、これはプロンプトマッチの順序を間違えると、やっぱり無限ループする。(モード前後でプロンプトが変化しない場合、特権モードのプロンプトを待ち続ける。)
    • ということで、無限(プロンプト待ち)ループを回避するために、一つのコマンドに対してのイベントループカウンタとかをいれて一定以上ループが回っている場合は強制終了させる、といった回避策を入れたりしてました。

そのほかいろいろ

上書き処理のあれこれ

こういう感じで、

conf term
no ip access-list HOGE
ip access-list HOGE
 permit ip ... ...
 deny ip ... ...

いったん消して再設定するようなコマンドを tftp で流し込むとかはよくやります。前提(初期状態)をそろえた上でコマンド生成してやったりする(前の状態に依存せずに処理を作る)方がやりやすいので。インタフェースとかも、いったん初期状態にしてから再設定とか。

conf term
default interface gi0/1
int gi0/1
 ip addr ...
end

これをやらない場合、前のコマンドとかぶるところは上書きされるし、かぶらないところはマージされるし…。
とはいえ、上の ACL 設定変更だって、こういういったんクリアして入れ直しという処理ではなくて、古い ACL を残しておいて、新しい ACL に切り替えた後、何か問題があったらすぐ戻せるようにしておきたい、みたいな話をされたこともあるし…(そうなると現在のコンフィグから処理を組み立てないといけないのでだいぶややこしくなる)。

まあ、あとはケースバイケースなんですが、

とかもあるので。そこを自動化するのかどうかという問題もあるのだけど。クリティカルだからこそ自動化する(テスト済みのオペレーションで回せるようにする)という話もあるので。何をどこまでやるのかは、目的に応じてちゃんと方針を考えないといけないです。

おわり

ということで、タレ…というかタレのレシピの一部分を公開してみました。

そうだよなあと思って探してみたんだけど、そこまで具体的な記録が見当たらなかった…。いや、うろ覚えの記憶はあるんだけど、うかつに書くと闇雲に dis ってしまいそうなんで…。あと、もうちょっと具体的な事例交えて説明できるとよいのだけど、そういうのをいろいろやっていたのはもうだいぶ前なので、うまいことぱっと出てこないんだよね…申し訳ねえ。

そうなんすよ。これのつらさを理解してもらいたいんですよホントに。

*1:どの時点でエラー処理をするか: 機器にコマンドを投げ込む前に止める? 投げ込んでからエラー見て止める?

*2:パラメタなし:デフォルトを使ったり明示的にパラメタ指定が必要なケースが混在するのをどう再利用するか