るつぼっと

NWエンジニアな人たちに向けて

[TextFSM] オプションフラグの仕組みと使い方

はじめに

ntc-templateを編集するために最近調べたので、自分なりに理解した内容を纏める。
参考にした文献は次のとおり。

TextFSM · google/textfsm Wiki · GitHub
21. Parsing command output with TextFSM — Python for network engineers 1.0 documentation

オプション一覧

ちゃんとした説明は公式サイトを参照。

  • Filldown
     対象Valueの現在行の解析結果が空だったら、前の行の値をコピーする。
  • Fillup
     対象Valueの前の行の解析結果が空だったら、今の行の値をコピーする。
  • Required
     このフラグのValueが空だと、今回の行の解析結果はテーブルに格納されない。
  • List
     値を複数保持する。これが無いと前の値は上書きされる。
  • Key
     使い道が分からんので今回はパス。

動作確認

作成したTemplate(test.template)を参照し、結果を出力するためのコード。
解析対象のデータも併せて定義している。

import textfsm

InputData = '''
2022_01_01 banana 100
           orange 200
           carrot 300
2022_12_31 banana 200
'''
with open('test.template') as template:
    fsm = textfsm.TextFSM(template)
    result = fsm.ParseText(InputData)

print(fsm.header)
print(*result, sep='\n')


基本とするTemplate

Value Date (\d+_\d+_\d+)
Value Item (\D+)
Value Qty (\d+)

Start
  ^${Date}\s*${Item}\s*${Qty} -> Record
  ^\s*${Item}\s*${Qty} -> Record


解析結果はこうなる。
インプットと同じく2~3行目は日付が空欄。

['Date', 'Item', 'Qty']
['2022_01_01', 'banana ', '100']
['', 'orange ', '200']
['', 'carrot ', '300']
['2022_12_31', 'banana ', '200']

Filldownオプション

Template
  • DateのValueFilldownオプションを付与
Value Filldown Date (\d+_\d+_\d+)
Value Item (\D+)
Value Qty (\d+)

Start
  ^${Date}\s*${Item}\s*${Qty} -> Record
  ^\s*${Item}\s*${Qty} -> Record
結果
['Date', 'Item', 'Qty']
['2022_01_01', 'banana ', '100']
['2022_01_01', 'orange ', '200']
['2022_01_01', 'carrot ', '300']
['2022_12_31', 'banana ', '200']
['2022_12_31', '', '']

Dataの空欄が埋まった。でも最後に余計な1行が出てきた。
暗黙のEOF Stateのせいだと思われるので次のとおりEOF Stateを明示的に定義して修正。
(このあたりの仕様の話は公式の説明を参照)

Template(EOF Stateを明示的に定義)
  • 末尾にEOF Stateを追記
Value Filldown Date (\d+_\d+_\d+)
Value Item (\D+)
Value Qty (\d+)

Start
  ^${Date}\s*${Item}\s*${Qty} -> Record
  ^\s*${Item}\s*${Qty} -> Record

EOF
結果
['Date', 'Item', 'Qty']
['2022_01_01', 'banana ', '100']
['2022_01_01', 'orange ', '200']
['2022_01_01', 'carrot ', '300']
['2022_12_31', 'banana ', '200']

最後の行が消えました。

Fillupオプション

Template
  • DateのValueFillupオプションを付与
Value Fillup Date (\d+_\d+_\d+)
Value Item (\D+)
Value Qty (\d+)

Start
  ^${Date}\s*${Item}\s*${Qty} -> Record
  ^\s*${Item}\s*${Qty} -> Record
結果
['Date', 'Item', 'Qty']
['2022_01_01', 'banana ', '100']
['2022_12_31', 'orange ', '200']
['2022_12_31', 'carrot ', '300']
['2022_12_31', 'banana ', '200']

最終行の2022_12_31の値が上方向の空欄に反映された。
挙動の仕組み上、今回はEOF Stateを明示する必要なし。

Requiredオプション

Template
  • DateのValueRequiredオプションを付与
Value Required Date (\d+_\d+_\d+)
Value Item (\D+)
Value Qty (\d+)

Start
  ^${Date}\s*${Item}\s*${Qty} -> Record
  ^\s*${Item}\s*${Qty} -> Record
結果
['Date', 'Item', 'Qty']
['2022_01_01', 'banana ', '100']
['2022_12_31', 'banana ', '200']

RequiredであるDateのValueがない行は格納されなくなった。

Listオプション

説明の前に具体的な活用例を示す。
Continueオプションと併せて使うため、下記の記事も参考にどうぞ。
[TextFSM] Rule Actionsの挙動確認 - るつぼっと

Template
  • ItemとQtyのValueListオプションを付与
  • 1行目にContinue.Record付きのルールを追加
    ^\dは「行頭が数字」という条件のため今回は日付有りの行が該当
  • その他の行はRecord無し
Value Date (\d+_\d+_\d+)
Value List Item (\D+)
Value List Qty (\d+)

Start
  ^\d -> Continue.Record
  ^${Date}\s*${Item}\s*${Qty} 
  ^\s*${Item}\s*${Qty} 
結果
['Date', 'Item', 'Qty']
['2022_01_01', ['banana ', 'orange ', 'carrot '], ['100', '200', '300']]
['2022_12_31', ['banana '], ['200']]

このとおり、同じ日付についてはItemやQtyの値が一つのリストに纏められた。
こういう使い方をするらしい。
と言ってもこれだけじゃ分からないので動作を整理してみる。

動作の流れ

【注意】
以降は文献や動作結果から想像した内容です。誤りがあるかもしれません。
また、説明の都合により次の言葉を独自に定義しています。

  • Output Table…Recordアクションにより値が格納される場所
  • Buffer…ルールで抽出した値がRecordで格納されるまでに一時保存される場所

1.
1行目のInputが1行目のルールと照合され、合致する。
Recordアクションが取られるが何もBufferされていないため何も格納されない。


2.
Continueアクションに基づき2行目のルールと照合され、合致する。
Valueに紐づく値がBufferへ格納される。
RecordアクションがないためOutput Tableには格納されない。


3.
2行目のInputが1,2行目のルールと照合され、合致しない。
続いて3行目のルールと照合され、合致する。
Valueに紐づく値がBufferへ格納される。
※ 今回はList形式のため値が追加される。List形式でない場合は値が上書きされる
RecordアクションがないためOutput Tableには格納されない。


4.
3行目のInputが1,2行目のルールと照合され、合致しない。
続いて3行目のルールと照合され、合致する。
Valueに紐づく値がBufferへ格納される。 RecordアクションがないためOutput Tableには格納されない。


5.
4行目のInputが1行目のルールと照合され、合致する。
Recordアクションが取られBufferされた値がOutput Tableへ格納される。


6.
Continueアクションに基づき2行目のルールと照合され、合致する。
Valueに紐づく値がBufferへ格納される。
RecordアクションがないためOutput Tableには格納されない。


7.
Inputを全行読み込んだため最後に暗黙のEOF Stateの処理が走る。
つまり、Bufferされた値がOutput Tableへ格納される。


以上。
こんな動作をしているものと想定してます。