APRESIA Technical Blog

生成AIを使ってTextFSMを作成してみた

はじめに

  • 過去に当社の自動化システムに関する記事を紹介しております。

APRESIAヘルパーライブラリーがネットワークの構築をお手伝い!
APRESIA テスト自動化システムのご紹介
バージョンアップ作業自動化事例紹介(株式会社エネルギア・コミュニケーションズ様)

  • 上記でご紹介いたしました自動化システムにおいては、本稿の<APRESIAヘルパーライブラリ―を使用したテストの流れ>に従って、テストやバージョンアップ作業等を行います。
  • <APRESIAヘルパーライブラリーを使用したテストの流れ> ③はGoogle社が開発したTextFSMというCLI出力からテンプレートに従って情報を抽出するpythonライブラリーを使用しております。
  • 本テンプレートはshowコマンド体系によってカスタマイズを行う必要があります。showコマンドによってかかるカスタマイズ工数はまちまちではありましたが、平均すると数時間程、要しておりました。
  • 生成AIを使用すれば、割と複雑なshowコマンド体系でもTextFSMテンプレートは1時間程(正解が早いタイミングで得られば数十秒レベル)で完成できることが分かりました。
  • 本記事では、TextFSMテンプレートを作成する上での生成AIの活用術をご紹介します。尚、生成AIはMicrosoft社製Copilot Proを使用しております。showコマンドは当社製品ApresiaNP3000 シリーズを使用しております。以下のコマンドリファレンスを参考にしております。https://www.apresia.jp/products/ent/np/pdf/CommandReference_AEOS-NP3000_1.10_TD61-8374.pdf

APRESIAヘルパーライブラリーを使用したテストの流れ

①APRESIA等のネットワーク機器に対して、showコマンドを実行します。
②ネットワーク装置からshowコマンド結果の応答があります。
③②の結果からパラメーターをTextFSMテンプレートを使用してパースします。
④TextFSMテンプレートを使用したパース結果がRecordされます。
⑤④の結果とあらかじめ準備しておいた期待値を比較してテスト結果を判定します。

生成AIへの依頼のコツ

生成AIへの依頼の仕方によってTextFSMの完成度は変わってきます。
いくつか依頼する時のコツを示します。
・showコマンドとshowコマンド結果の対のサンプルを添付してTextFSMの作成依頼をする。
・空白や改行など、あらかじめ考慮して作成するように依頼をする。

基本形と、結果が一行ではなく複数行で返ってくる形の2パターンについて実行してみました。

TextFSM作成依頼事例1:基本形

■生成AIへの質問内容
L3スイッチ上で、コマンド show ip route を実行したときのコマンド出力結果から、TextFSM の テンプレートファイルを作成して頂けませんか?
条件としては、以下の3点を考慮してください。

  • 複数の空白にマッチさせる場合は、\s+ を使用してください。・・・Tips①
  • viaが無く、is directly connected になっているエントリがあることに注意して下さい。・・・Tips②
  • TypeがOの時は、O IA など、空白が間に入る場合があること(\S+ではヒットしないこと)に注意してください。・・・Tips③
# show ip route
Code: C - connected, S - static, R - RIP, B - BGP, O - OSPF,
IA - OSPF inter area,
N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2,
E1 - OSPF external type 1, E2 - OSPF external type 2,
* - candidate default
 
Gateway of last resort is 10.1.0.2 to network 0.0.0.0
S       192.168.100.0/24 [60/1] via 192.168.10.2, vlan30
S       192.168.200.0/24 [60/1] via 192.168.10.2, vlan30
O*E2    0.0.0.0/0 [115/20] via 10.1.0.2, vlan10
C       10.1.0.0/24 is directly connected, vlan10
O       10.1.1.0/24 [80/2] via 10.1.0.2, vlan10
O IA    10.1.101.0/24 [90/2] via 10.1.0.2, vlan10
O E1    10.1.201.0/24 [110/21] via 10.1.0.2, vlan10
O E2    10.1.211.0/24 [115/20] via 10.1.0.2, vlan10
C       172.16.10.0/24 is directly connected, vlan20
R       172.16.200.0/24 [100/2] via 172.16.10.2, vlan20
C       192.168.10.0/24 is directly connected, vlan30
Total Entries: 11

■Tips
①この条件が無いと、${Type}     ${Destination}のように空白を重ねてしまい、空白の数が異なるフォーマットのデータを取得できない場合があります。

②この条件が無いと、「is directly connected」の行を取得できずエントリ出力してくれません。

③この条件が無いと、Typeとして、\S+を使用してしまい、「O IA」の行がうまく取得できずエントリ出力してくれません。

■生成AIからの回答結果
ご指定いただいた条件に基づいて、TextFSMのテンプレートを作成しました。以下に示すように、各ルートエントリのタイプ、宛先、プレフィックス、メトリック、ネクストホップ、インターフェースを抽出します。
Value Required Type (\S+.*)
Value Required Destination (\S+)
Value Prefix (\S+)
Value Metric (\S+)
Value Filldown NextHop (\S+)
Value Interface (\S+)

Start
^\s*${Type}\s+${Destination}/${Prefix}\s+\[${Metric}\]\s+via\s+${NextHop},\s+${Interface} -> Record
^\s*${Type}\s+${Destination}/${Prefix}\s+is directly connected,\s+${Interface} -> Record
このテンプレートは、show ip routeコマンドの出力を解析し、各ルートエントリの詳細を抽出します。また、Typeフィールドは\S+.*を使用しており、空白を含むエントリ(例:O IA)も適切にマッチします。

ただし、このテンプレートはあくまで一例であり、実際のネットワーク環境や要件によって調整が必要な場合があります。必要に応じてテンプレートをカスタマイズしてご利用ください。また、TextFSMの詳細な使用方法については、公式ドキュメンテーションをご参照ください。

■回答結果の手動による手直し
Templateとしては不完全のため、以下の点を手動で手直しを行い完成させました。



■Tips
④RequiredがついているValueに値が入っていない場合、Recordされません。これによって最終ValueのEntriesがRecordされない事象が発生してしまうため、Requiredを削除しました。

⑤例えば以下の2つの行において上の段はvia 10.1.0.2でという形でNexthopが定義されていますが、下の段はNexthopが定義されておりません。Filldownが入っていることで上段のNexthopの値が下段の配列に入力されてしまうため、削除しました。
O*E2    0.0.0.0/0 [115/20] via 10.1.0.2, vlan10
C       10.1.0.0/24 is directly connected, vlan10

⑥Valueの定義の意味合いがInterfaceよりもVLAN_IDが相応しいため、修正しました。

⑦Entriesがなかったため、Entriesもパースできるように修正しました。

■完成形
Value Type (\S+.*)
Value Destination (\S+)
Value Prefix (\S+)
Value Metric (\S+)
Value NextHop (\S+)
Value Vlanid (\S+)
Value Entries (\S+)

Start
  ^\s*${Type}\s+${Destination}/${Prefix}\s+\[${Metric}\]\s+via\s+${NextHop},\s+${Vlanid} -> Record
  ^\s*${Type}\s+${Destination}/${Prefix}\s+is directly connected,\s+${Vlanid} -> Record
  ^Total Entries:\s+${Entries} -> Record

TextFSM作成依頼事例2:結果が複数行で表示される形

■生成AIへの依頼内容
L3スイッチ上で、コマンド show vlan private-vlanを実行したときのコマンド出力結果から、TextFSM のテンプレートファイルを作成して頂けませんか?
結果が複数行で表示される出力結果のサンプルと、本出力結果から作成したTextFSMテンプレートのサンプルを添付しますので、これを元に考えてください。

◇結果が複数行で表示される出力結果のサンプル
lag  description
1  Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
2  Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur.

◇上記出力結果から作成したTextFSMテンプレートのサンプル
Value lag (\d+)
Value List description ([\w\-,\.\s]+)
Start
^\s*${lag}\s+${description} -> ContinueLineProcessing
ContinueLineProcessing
^\s{5,}(${description})
^\s*\d+[\w\-,.\s]+ -> Continue.Record
^\s*${lag}\s+${description} -> ContinueLineProcessing

◇show vlan private-vlanを実行したときのコマンド出力結果
# show vlan private-vlan
Primary VLAN   Secondary VLAN   Type      Interface
-----------------------------------------------------
300            200              Isolated    1/0/9-1/0/10,1/0/12-1/0/13,
1/0/15-1/0/16,1/0/24,
1/0/26-1/0/27,1/0/32
300            100              Community   1/0/1-1/0/8,1/0/24
Total Entries: 2

■生成AIからの回答結果
ご提供いただいた情報を元に、show vlan private-vlanコマンドの出力結果からTextFSMテンプレートを作成します。
Value Required Primary_VLAN (\d+)
Value Required Secondary_VLAN (\d+)
Value Required Type (\w+)
Value List Interface ([\d\/\-,]+)

Start
^\s*Primary VLAN\s+Secondary VLAN\s+Type\s+Interface -> Begin

Begin
^\s*${Primary_VLAN}\s+${Secondary_VLAN}\s+${Type}\s+${Interface} -> ContinueLineProcessing

ContinueLineProcessing
^\s{5,}(${Interface})
^\s*\d+[\d\/\-,]+ -> Continue.Record
^\s*${Primary_VLAN}\s+${Secondary_VLAN}\s+${Type}\s+${Interface} -> ContinueLineProcessing
このテンプレートは、show vlan private-vlanコマンドの出力結果を解析し、各VLANの情報を抽出します。各行が新しいVLANの開始を示す場合、または同じVLANの追加インターフェース情報が続く場合に対応しています。このテンプレートは、出力結果の形式によりますので、必要に応じて調整してください。また、このテンプレートはあくまで一例ですので、実際の環境や要件に合わせてカスタマイズしてご使用ください。ご不明な点がございましたら、お気軽にお問い合わせください。よろしくお願いいたします。

■回答結果の手動による手直し
Templateとしては不完全のため、以下の点を手動で手直しを行い完成させました。


■Tips
⑧RequiredがついているValueに値が入っていない場合、Recordされません。これによって最終ValueのEntriesがRecordされない事象が発生してしまうため、Requiredを削除しました。

⑨基本形のTips⑦で示したEntriesとは違う追加方法で設定しております。本件、TextFSM内の動きを解説しながら以下に示します。尚、テンプレートポインターとCLIポインターという用語を交えながら内部プログラムの動きを説明します。(少し長文解説となりますが、失礼します。)

(ⅰ) テンプレートポインターは、ラベルBeginから^\\s*${Primary_VLAN}\\s+${Secondary_VLAN}\\s+${Type}\\s+${Interface} -> ContinueLineProcessingというルールにヒットする行を探します。
300            200              Isolated    1/0/9-1/0/10,1/0/12-1/0/13,
・この行では、Primary_VLANSecondary_VLANTypeInterfaceの値として内部のテンポラリー領域に保存されます。(尚、InterfaceはValue List Interface と定義されているため、List形式で保存されます。)
・ テンプレートポインターは、ラベルContinueLineProcessingに遷移します。

(ⅱ) テンプレートポインターは^\\s{5,}(${Interface})というルールにヒットする行を探します。
・5つ以上のスペースで始まるCLI出力の以下の行がこのルールにヒットします。(CLIポインターはこの位置まで進みます。)
                                                1/0/15-1/0/16,1/0/24,
・本値がInterfaceの値としてList形式で追加されて内部のテンポラリー領域に保存されます。

(ⅲ) テンプレートポインターはラベルContinueLineProcessing内で^\\s{5,}(${Interface})にヒットする行が続く限り、ステップ(ⅱ)を繰り返します。以下の行がヒットして本値がInterfaceの値として(ⅱ)同様に、List形式で追加されて内部のテンポラリー領域に保存されます。(CLIポインターはこの位置まで進みます。)
                                                 1/0/26-1/0/27,1/0/32

(ⅳ) テンプレートポインターは^\\s*\\d+\[\\d\\/\\-,\]+ -> Continue.Recordというルールにヒットする行を探します。
Continue.Recordのアクションにより、現在までのレコードが出力されて以下のように配列保存されます。
[['300','200','Isolated', ['1/0/9-1/0/10,1/0/12-1/0/13,','1/0/15-1/0/16,1/0/24,','1/0/26-1/0/27,1/0/32'],''],
]

(ⅴ) テンプレートポインターは^\\s*${Primary_VLAN}\\s+${Secondary_VLAN}\\s+${Type}\\s+${Interface} -> ContinueLineProcessingというルールにヒットする行を探して以下を見つけます。(CLIポインターはこの位置まで進みます。)
300            100              Community   1/0/1-1/0/8,1/0/24
・ここでPrimary_VLANSecondary_VLANTypeInterfaceの値として内部のテンポラリー領域に保存します。
・ テンプレートポインターはラベルContinueLineProcessingに戻ります。

(ⅵ) CLIポインターが次行のTotal Entries:手前まで進んでいるため、 テンプレートポインターは以下のルールにはヒットせず、素通りします。
^\s{5,}(${Interface})
^\s*\d+[\d\/\-,]+ -> Continue.Record
^\s*${Primary_VLAN}\s+${Secondary_VLAN}\s+${Type}\s+${Interface} -> ContinueLineProcessing

(ⅶ)次にテンプレートポインターは^\s*Total Entries -> Continue.Recordというルールにヒットする行を探します。以下の行にヒットします。(CLIポインターはこの位置まで進みます。)
Total Entries: 2
Continue.Recordのアクションにより、(ⅴ)でテンポラリー保存された値が出力されて(ⅳ)の配列に追加保存します。
[['300','200','Isolated', ['1/0/9-1/0/10,1/0/12-1/0/13,','1/0/15-1/0/16,1/0/24,','1/0/26-1/0/27,1/0/32'],''],
['300',’100’,’Community', ['1/0/1-1/0/8,1/0/24'],''],
]
・ テンプレートポインターは次の行に進みます。

(ⅷ) テンプレートポインターは最終行の^\s*Total Entries:\s+${TotalEntries}というルールにヒットしてテンポラリー保存します。
・CLIポインターは最終行まで到達するとTextFSMの暗黙のルール(EOF:End Of File)により、テンポラリー保存されたTotalEntiresの値も配列に追加保存します。
・showコマンドのリプライ内容は、最終的に以下のように配列保存されます。
[['300','200','Isolated', ['1/0/9-1/0/10,1/0/12-1/0/13,','1/0/15-1/0/16,1/0/24,','1/0/26-1/0/27,1/0/32'],''],
['300',’100’,’Community', ['1/0/1-1/0/8,1/0/24'],‘’],
['','','', [],‘2’],
]

上記のように結果が複数行表示される事例2においては、事例1の基本形とは違って、最終行のTotalEntriesを配列補完させるための工夫が必要になります。

■完成形
Value Primary_VLAN (\d+)
Value Secondary_VLAN (\d+)
Value Type (\w+)
Value List Interface ([\d\/\-,]+)
Value TotalEntries (\d+)

Start
  ^\s*Primary VLAN\s+Secondary VLAN\s+Type\s+Interface -> Begin

Begin
  ^\s*${Primary_VLAN}\s+${Secondary_VLAN}\s+${Type}\s+${Interface} -> ContinueLineProcessing

ContinueLineProcessing
  ^\s{5,}(${Interface})
  ^\s*\d+[\d\/\-,]+ -> Continue.Record
  ^\s*${Primary_VLAN}\s+${Secondary_VLAN}\s+${Type}\s+${Interface} -> ContinueLineProcessing
  ^\s*Total Entries -> Continue.Record
  ^\s*Total Entries:\s+${TotalEntries}

おわりに

生成AIを活用したTextFSMテンプレートの作成におけるポイントを以下にまとめます。

  • TextFSMテンプレートとして、正しい結果が得られるまで生成AIへの質問は複数回、試行してください。もしくは、ある程度正しい結果が得られた時点で手動による補足を行い、完成させてください。
  • コマンドリファレンスのようなマニュアルの記述を抜粋してテストを行うと空白や改行などにより文字がずれる要因になり、テスト結果が正しくてもfailedとなることがあります。最終チェックは実機からの出力結果を使用してテストを試行してください。