TextFSMCodeLab.wiki#
https://code.google.com/archive/p/textfsm/wikis/TextFSMCodeLab.wiki
Overview#
このコードラボは、TextFSMpythonモジュールのユーザーが新しいテンプレートを作成するのに役立つように設計されています。この柔軟な汎用テキストパーサーは、主にPythonでルーターCLIコマンドの出力を解析するために使用されます。比較的単純な正規表現ベースのテキストファイルを作成することにより、最小限のコードで多数のコマンド出力を解析できます。
このコードラボは、単純なルーターコマンドの出力から始まり、テンプレートを正常に記述して単純なPythonスクリプトで使用するために必要な手順を説明します。
Pythonの基本をすでに理解していて、TextTableFSMのハウツーページを読んで、参照用に開いておく必要があります。
基本的なテキスト#
最初の例では、単純な線形(行ベースではない)テキスト(Ciscoの「showclock」の出力)を解析します。
実際の日付/時刻のみが解析されます。プロンプトは解析されません。ここで抽出したい情報は次のとおりです。 * 年 * 曜日 * 月 * タイムゾーン * 時間(秒まで)これらの情報の各ビットは、独自のFSM '値'に抽出され、それを使用するPythonスクリプトでそれぞれを個別に使用できるようになります。この例では、意図的に平日と一致させようとはしません。したがって、最初に行う必要があるのは、テンプレートに「値」の行を入力することです。
cisco_clock_template
と呼ばれる新しいファイルを開き、次の行をそのファイルに挿入します。
これらはValueの定義です。各行の最初の単語はキーワード「Value」であり、その行が行の列を定義していることをtextFSMに通知します。次の単語は値の名前です。これは任意の英数字の単語にすることができます。最後に、少なくとも1つのパレンラップされた式を含む正規表現があります。これらは、必要な値に正確に一致する正規表現を含む部分式です。たとえば、は(\d+)年を表す数字のシーケンスと一致します。
Time
値の定義の後に空白行を挿入します。これは、「Value」の定義の終わりを示します。この後、textFSMの状態の定義を開始します。状態「開始」は常に必要であり、textFSMは最初にテキストを解析するときにここから開始します。したがって、textFSMの次の行には「Start」という1つの単語があります。
Value Year(\ d +)
Value MonthDay(\ d +)
Value Month(\ w +)
Value Timezone(\ S +)
Value Time(..:..:..)
- Start
状態ラベルに続いて、1つ以上のルールを挿入します。ステートマシンが新しい状態に入ると、現在の入力行を取得し、それを各ルールと順番に照合しようとします。一致すると、任意の「値」が置き換えられ、オプションのアクションが実行されます。このテンプレートにはルールが1つしかないため、次のようにテンプレートを完成させて、cisco_clock_template
に次のように保存します。
Value Year(\ d +)
Value MonthDay(\ d +)
Value Month(\ w +)
Value Timezone(\ S +)
Value Time(..:..:..)
Start ^${Time}.* ${Timezone} \w+ ${Month} ${MonthDay} ${Year} -> Record
内部的には、値への参照が値で指定された正規表現に置き換えられるように、ルールが拡張されます。このテンプレートの単一のルールは、この正規表現に内部的に展開されます。
1行の入力(18:42:41.321 PST Sun Feb 8 2009)が適用されると、正規表現が一致し、各正規表現一致グループには次の値が含まれます。
| グループ | 値 | |:---------- |:---------- | | 1 | 18:42:41 2 PST 3 2月 4 8 5 2009 |
一致が成功したため、グループに関連付けられている各値に一致するテキストが割り当てられます。これにより、1つの(そして唯一の)行が埋められます。
関連するアクションレコードもあります。これは、FSMに行をファイナルテーブルに挿入するように指示します。暗黙の「次へ」アクションもあります(FSMにテキストの次の行を読み取るように指示するTextTableFSMを参照してください。これ以上テキストがないため(1行しかない)、FSMは完了し、一致した1行だけを返します。
いくつかの入力テキストでFSMを試します。
$ cat > router_output.txt 18:42:41.321 PST Sun Feb 8 2009
$ ./textfsm.py cisco_clock_template router_output.txt
# FSM Template:
Value Year (\d+)
Value MonthDay (\d+)
Value Month (\w+)
Value Timezone (\S+)
Value Time (..:..:..)
Start ^${Time}.* ${Timezone} \w+ ${Month} ${MonthDay} ${Year} -> Record
FSM Table:#
成功!出力の最初のセクションは解析されたFSMを示し、最後のセクションはファイナルテーブルを示します。このテーブルの最初の行はヘッダーであり、定義した列(または「値」)を示しています。次の行は、一致した値の行です。
複数行#
ここで、もう少し複雑なもの、つまり複数行のテキストからの値の一致について見ていきます。このために、Ciscoの「show version」コマンドの出力を解析しようとします。これは次のようになります。
Cisco IOS Software, Catalyst 4500 L3 Switch Software (cat4500-ENTSERVICESK9-M), Version 12.2(31)SGA1, RELEASE SOFTWARE (fc3) Technical Support: http://www.cisco.com/techsupport Copyright (c) 1986-2007 by Cisco Systems, Inc. Compiled Fri 26-Jan-07 14:28 by kellythw Image text-base: 0x10000000, data-base: 0x118AD800
ROM: 12.2(31r)SGA Pod Revision 0, Force Revision 34, Gill Revision 20
router.abc uptime is 11 weeks, 4 days, 20 hours, 26 minutes System returned to ROM by reload System restarted at 22:49:40 PST Tue Nov 18 2008 System image file is "bootflash:cat4500-entservicesk9-mz.122-31.SGA1.bin"
This product contains cryptographic features and is subject to United States and local country laws governing import, export, transfer and use. Delivery of Cisco cryptographic products does not imply third-party authority to import, export, distribute or use encryption. Importers, exporters, distributors and users are responsible for compliance with U.S. and local country laws. By using this product you agree to comply with applicable laws and regulations. If you are unable to comply with U.S. and local laws, return this product immediately.
A summary of U.S. laws governing Cisco cryptographic products may be found at: http://www.cisco.com/wwl/export/crypto/tool/stqrg.html
If you require further assistance please contact us by sending email to export@cisco.com.
cisco WS-C4948-10GE (MPC8540) processor (revision 5) with 262144K bytes of memory. Processor board ID FOX111700ZN MPC8540 CPU at 667Mhz, Fixed Module Last reset from Reload 2 Virtual Ethernet interfaces 48 Gigabit Ethernet interfaces 2 Ten Gigabit Ethernet interfaces 511K bytes of non-volatile configuration memory.
Configuration register is 0x2102
これからいくつかの情報を抽出します。 * Software version * System uptime * Configuration register * Reset reason
これにより、テーブルに4つの列が作成されます(最終的には1つの行になります)。まず、「Value」ステートメントを定義します。'cisco_version_template'という名前の新しいファイルから始めて、次のファイルをそのファイルに挿入します。
Value Version ([^ ,]+)
Value Uptime (.)
Value ConfigRegister (\w+)
Value ResetReason (.)
Start ^Cisco IOS .*Version ${Version}, ^.*uptime is ${Uptime} ^Last reset from ${ResetReason} ^Configuration register is ${ConfigRegister} -> Record
これは、最初の例よりも少し複雑です。最も重要なことは、テンプレートが一部の入力行にのみ一致することです。入力の各行について、状態の各ルールがチェックされます。ルールに一致するものがない場合、FSMは単に次のルールに移動します。すべてのルールがチェックされると(この場合、「構成レジスタ」ルールの後)、入力の次の行がフェッチされ、ルールは状態の最初から再度チェックされます。
したがって、ここでは次のことが起こります。 入力の最初の行が一致し、「バージョン」の値に「12.2(31)SGA1」が割り当てられます。'uptime is'行まで、他のすべての行は一致せず、破棄されます。「uptime」行が一致し、「Uptime」に「11 weeks, 4 days, 20 hours, 26 minute」が割り当てられます。「Lastreset」行まで、行が一致しないため破棄されます。この時点で、一致し、「ResetReason」値が割り当てられます。「Reload」「ConfigRegister」が割り当てられるまで、さらに数行が渡されます。「0x2102」この行も「Record」アクションをトリガーし、行が保存されます。この行の後、EOFに到達し、FSMが終了します。テンプレートを保存し、ルーターの出力を「router_output.txt」にコピーした後、FSMに対して実行します。
$;./textfsm.py cisco_version_template router_output.txt
FSM Template:
Value Version ([^ ,]+)
Value Uptime (.)
Value ConfigRegister (\w+)
Value ResetReason (.)
Start ^Cisco IOS .*Version ${Version}, ^.*uptime is ${Uptime} ^Last reset from ${ResetReason} ^Configuration register is ${ConfigRegister} -> Record
FSM Table:
['Version', 'Uptime', 'ConfigRegister', 'ResetReason']
['12.2(31)SGA1', '11 weeks, 4 days, 20 hours, 26 minutes', '0x2102', 'Reload']
表形式データの解析#
前の例は、FSMの最も単純なアプリケーションを示しました-繰り返されないデータを単一の行に解析します。この例では、より興味深い例を見ていきます。Juniperコマンドの出力showchassisfpcが解析されます。1つのデバイスからの生のルーター出力は次のようになります。
Temp CPU Utilization (%) Memory Utilization (%) Slot State (C) Total Interrupt DRAM (MB) Heap Buffer 0 Online 24 7 0 256 38 51 1 Online 25 7 0 256 38 51 2 Online 24 3 0 256 37 49 3 Online 23 3 0 256 37 49 4 Empty 5 Empty 6 Empty 7 Empty
このテキストは簡単に解析できます。その情報は別々の行にきちんと含まれており、FSMデータは常に行として表示されます。この互換性により、比較的簡単なテンプレート作成が保証されます。このアプリケーションでは、定義されたFPCごとに1行のデータを作成しますが、テキストはFPCスロットごとに1行で表示されるため、これは簡単です。 抽出したい情報は次のとおりです。
- Slot number
- State
- Temperature
- DRAM
- Buffer utilisation
これにより、5つの関心のある値が得られます。新しいファイルjuniper_fpc_templateを作成し、最初に次の値の定義をそのファイルに入力します。
次に、状態の定義と関連するルールを入力します。1つのルールで逃げることができるかもしれません。
Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
#貪欲なマッチングはそれを壊すので、未使用のプレースホルダーに。*を使用することはできません
State
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record
上記の生のルーター出力をrouter_output.txtにコピーし、テンプレートを保存して実行します。
$ ./textfsm.py juniper_fpc_template router_output.txt FSM
Template: Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record
FSM Table:
['Slot', 'State', 'Temperature', 'DRAM', 'Buffer']
['0', 'Online', '24', '256', '51'] ['1', 'Online', '25', '256', '51']
['2', 'Online', '24', '256', '49'] ['3', 'Online', '23', '256', '49']
テンプレートは、すべてのオンラインFPCスロットを正常に解析し、正しい値を抽出しました。#
しかし、空のスロットはどうですか?すべてのスロットに関する情報も抽出する必要がある場合、空のスロットにはSlot列とState列しかないため、ここには表示されません。これに対処する方法は、これらの行をキャッチするための2番目のルールを作成することです。 次のように、既存のルールの後にもう1つのルールを追加します。
Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
# 貪欲なマッチングはそれを壊すので、未使用のプレースホルダーに。*を使用することはできません。
State
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
次にFSMを実行します。
$;./textfsm.py juniper_fpc_template router_output.txt
FSM Template: Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
FSM Table: ['Slot', 'State', 'Temperature', 'DRAM', 'Buffer'] ['0', 'Online', '24', '256', '51'] ['1', 'Online', '25', '256', '51'] ['2', 'Online', '24', '256', '49'] ['3', 'Online', '23', '256', '49'] ['4', 'Empty', '', '', ''] ['5', 'Empty', '', '', ''] ['6', 'Empty', '', '', ''] ['7', 'Empty', '', '', '']
成功!これで、埋められたスロットと空のスロットの両方に関する情報が抽出されました。
「Filldown'」の使用#
showchassis fpcからテーブルを抽出できるようになったので、拡張を行う必要があります。上記の簡単な例では機能しますが、次のようなジュニパーTXマトリックスからのより複雑な出力には完全に効果的ではありません。
lcc0-re0:
Temp CPU Utilization (%) Memory Utilization (%)
Slot State (C) Total Interrupt DRAM (MB) Heap Buffer 0 Online 24 8 1 512 16 52 1 Online 23 7 1 256 36 53 2 Online 23 5 1 256 36 49 3 Online 21 7 1 256 36 49 4 Empty 5 Empty 6 Empty 7 Empty
lcc1-re1:
Temp CPU Utilization (%) Memory Utilization (%)
Slot State (C) Total Interrupt DRAM (MB) Heap Buffer 0 Online 20 9 1 256 36 50 1 Online 20 13 0 256 36 49 2 Online 21 6 1 256 36 49 3 Online 20 6 0 256 36 49 4 Online 18 5 0 256 35 49 5 Empty 6 Empty 7 Empty
このノードには2つの物理シャーシ(lcc0-re0とlcc1-re0)があり、各スロット番号が2つあり、シャーシごとに1つあります。
この出力をFSMに対して実行すると、次のように表示されます。
FSM Template: Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start
^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
FSM Table:
['Slot', 'State', 'Temperature', 'DRAM', 'Buffer'] ['0', 'Online', '24', '512', '52'] ['1', 'Online', '23', '256', '53'] ['2', 'Online', '23', '256', '49'] ['3', 'Online', '21', '256', '49'] ['4', 'Empty', '', '', ''] ['5', 'Empty', '', '', ''] ['6', 'Empty', '', '', ''] ['7', 'Empty', '', '', ''] ['0', 'Online', '20', '256', '50'] ['1', 'Online', '20', '256', '49'] ['2', 'Online', '21', '256', '49'] ['3', 'Online', '20', '256', '49'] ['4', 'Online', '18', '256', '49'] ['5', 'Empty', '', '', ''] ['6', 'Empty', '', '', ''] ['7', 'Empty', '', '', '']
残念ながら、512Mb FPCがlcc0またはlcc1にあるかどうかを確認する方法はありません。これは、シャーシ情報を保存していないためです。したがって、^ S +:に一致する別の値 'Chassis'を追加することでこれを行うことができます。新しい値とルールを追加して、テンプレートを更新します。
Value Chassis (\S+) Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^${Chassis}: ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
しかし、これを実行すると、わずかな問題が発生します。
FSM Template: Value Chassis (\S+) Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^${Chassis}: ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
FSM Table: ['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer'] ['lcc0-re0', '0', 'Online', '24', '512', '52'] ['', '1', 'Online', '23', '256', '53'] ['', '2', 'Online', '23', '256', '49'] ['', '3', 'Online', '21', '256', '49'] ['', '4', 'Empty', '', '', ''] ['', '5', 'Empty', '', '', ''] ['', '6', 'Empty', '', '', ''] ['', '7', 'Empty', '', '', ''] ['lcc1-re1', '0', 'Online', '20', '256', '50'] ['', '1', 'Online', '20', '256', '49'] ['', '2', 'Online', '21', '256', '49'] ['', '3', 'Online', '20', '256', '49'] ['', '4', 'Online', '18', '256', '49'] ['', '5', 'Empty', '', '', ''] ['', '6', 'Empty', '', '', ''] ['', '7', 'Empty', '', '', '']
「シャーシ」列は、各シャーシの最初のスロットにのみ入力されます。どうして?
問題は、「レコード」アクションが実行されるたびに、行が保存されてから、各値がクリアされることです。したがって、対応する行が入力されて保存されると、「シャーシ」ルールに一致するものがなくなるため、ルーター出力の次のシャーシ仕様までこれが入力されることはありません。
これを修正するために、Chassis値に「Filldown」オプションを追加します。このオプションは、各「レコード」の後に値を保持するようにFSMに指示するため、値はクリアされません。その値は、「Clearall」アクションがある場合、またはルールが値を上書きする場合にのみ変更されます。
次のように、「Filldown」オプションを使用してChassisValue行を変更します。
次に、FSMを介してテキストを再度実行します。
$; /textfsm.py juniper_fpc_template router_output.txt FSM Template: Value Filldown Chassis (\S+) Value Slot (\d) Value State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^${Chassis}: ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
FSM Table: ['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer'] ['lcc0-re0', '0', 'Online', '24', '512', '52'] ['lcc0-re0', '1', 'Online', '23', '256', '53'] ['lcc0-re0', '2', 'Online', '23', '256', '49'] ['lcc0-re0', '3', 'Online', '21', '256', '49'] ['lcc0-re0', '4', 'Empty', '', '', ''] ['lcc0-re0', '5', 'Empty', '', '', ''] ['lcc0-re0', '6', 'Empty', '', '', ''] ['lcc0-re0', '7', 'Empty', '', '', ''] ['lcc1-re1', '0', 'Online', '20', '256', '50'] ['lcc1-re1', '1', 'Online', '20', '256', '49'] ['lcc1-re1', '2', 'Online', '21', '256', '49'] ['lcc1-re1', '3', 'Online', '20', '256', '49'] ['lcc1-re1', '4', 'Online', '18', '256', '49'] ['lcc1-re1', '5', 'Empty', '', '', ''] ['lcc1-re1', '6', 'Empty', '', '', ''] ['lcc1-re1', '7', 'Empty', '', '', ''] ['lcc1-re1', '', '', '', '', '']
これで、シャーシの値がすべて「入力済み」になりました。1つの問題を除いてほぼ完璧です。テーブルの下部に、ほとんど空の奇妙な行があります。そこで何をしているのですか?
「Required」の使用#
その行は、Filldownオプションが原因で発生します。最後の有効な行が保存されると(lcc-re1、スロット7)、FSMは値を入力する準備ができた新しい空の行を作成します。通常、FSMは終了時に空の行を破棄しますが、この場合は「Filldown」オプション'Chassis'列にデータが入力されているため、FSMはこの空でない行を保持し、FSMが終了したときに保存します。
これを修正するために、別の値オプション(必須)を使用します。このオプションは、値が一致している必要があることを指定します。一致していない場合、行は保存されません。このテンプレートでは、「slot」と「state」の両方に値が含まれていることを確認するため、次のように変更します。
Value Required Slot (\d) Value Required State (\w+) Now we finally have a correct table:
FSM Template: Value Filldown Chassis (\S+) Value Required Slot (\d) Value Required State (\w+) Value Temperature (\d+) Value DRAM (\d+) Value Buffer (\d+)
Start ^${Chassis}: ^\s+${Slot}\s+${State}\s+${Temperature}\s+\d+\s+\d+\s+${DRAM}\s+\d+\s+${Buffer} -> Record ^\s+${Slot}\s+${State} -> Record
FSM Table:
['Chassis', 'Slot', 'State', 'Temperature', 'DRAM', 'Buffer'] ['lcc0-re0', '0', 'Online', '24', '512', '52'] ['lcc0-re0', '1', 'Online', '23', '256', '53'] ['lcc0-re0', '2', 'Online', '23', '256', '49'] ['lcc0-re0', '3', 'Online', '21', '256', '49'] ['lcc0-re0', '4', 'Empty', '', '', ''] ['lcc0-re0', '5', 'Empty', '', '', ''] ['lcc0-re0', '6', 'Empty', '', '', ''] ['lcc0-re0', '7', 'Empty', '', '', ''] ['lcc1-re1', '0', 'Online', '20', '256', '50'] ['lcc1-re1', '1', 'Online', '20', '256', '49'] ['lcc1-re1', '2', 'Online', '21', '256', '49'] ['lcc1-re1', '3', 'Online', '20', '256', '49'] ['lcc1-re1', '4', 'Online', '18', '256', '49'] ['lcc1-re1', '5', 'Empty', '', '', ''] ['lcc1-re1', '6', 'Empty', '', '', ''] ['lcc1-re1', '7', 'Empty', '', '', '']
「List」の使用#
多くの場合、特定の列に値のリストを含める必要があります。たとえば、ルーティングテーブルを解析する場合、プレフィックスごとに複数のネクストホップが存在する可能性があります。以下の例は、この例の目的のために簡略化された、そのようなルーティングテーブルです。
Destination Gateway Dist/Metric Last Change
----------- ------- ----------- -----------
B EX 0.0.0.0/0 via 192.0.2.73 20/100 4w0d via 192.0.2.201 via 192.0.2.202 via 192.0.2.74
B IN 192.0.2.76/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.204/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.80/30 via 203.0.113.183 200/100 4w2d
B IN 192.0.2.208/30 via 203.0.113.183 200/100 4w2d
この例では、次の情報を抽出します。
- Protocol
- Type
- Destination prefix
- Gateway (for simplicity's sake we will assume all entries will be of the form "via a.b.c.d")
- Distance
- Metric
- Last Change
上記のルーティングテーブルの出力を「routes.txt」というファイルにコピーします。 データを抽出するための単純なFSMを構築します。以下のテキストを「routes.tmpl」というファイルに入れます。
Value Protocol (\S) Value Type (\S\S) Value Required Prefix (\S+) Value Gateway (\S+) Value Distance (\d+) Value Metric (\d+) Value LastChange (\S+)
Start ^.*----- -> Routes
Routes ^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange} -> Record
上記の「開始」状態では、ダッシュの行に特別な一致があることに注意してください。これにより、ヘッダーが完了するまで入力テキストが暗黙的に破棄されます。これは実際には必要ないか、この場合ですが、ヘッダーデータが実際の行データと混同される可能性がある他の場合を示すのに役立ちます。
次に、データに対してテンプレートを実行します。
$ ./textfsm.py route.tmpl routes.txt FSM Template: Value Protocol (\S) Value Type (\S\S) Value Prefix (\S+) Value Gateway (\S+) Value Distance (\d+) Value Metric (\d+) Value LastChange (\S+)
Start ^.*----- -> Routes
Routes ^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange} -> Record
FSM Table: ['Protocol', 'Type', 'Prefix', 'Gateway', 'Distance', 'Metric', 'LastChange'] ['B', 'EX', '0.0.0.0/0', '192.0.2.73', '20', '100', '4w0d'] ['B', 'IN', '192.0.2.76/30', '203.0.113.183', '200', '100', '4w2d'] ['B', 'IN', '192.0.2.204/30', '203.0.113.183', '200', '100', '4w2d'] ['B', 'IN', '192.0.2.80/30', '203.0.113.183', '200', '100', '4w2d'] ['B', 'IN', '192.0.2.208/30', '203.0.113.183', '200', '100', '4w2d']
テーブルはほとんどいっぱいです...デフォルトのプレフィックスの最初のゲートウェイしか表示されないことを除いて。テンプレートが他のゲートウェイを定義する行と一致しない理由は簡単にわかります。では、これを回避する方法は?
オプション「リスト」は、単一の文字列ではなく文字列のリストとして列を指定するために使用できるため、ここで役立ちます。したがって、このオプションを「ゲートウェイ」値の定義に追加します。
Value Protocol (\S) Value Type (\S\S) Value Required Prefix (\S+) Value List Gateway (\S+) Value Distance (\d+) Value Metric (\d+) Value LastChange (\S+) Run it again, and we see that the Gateway columns are now a list, albeit with one entry:
FSM Table: ['Protocol', 'Type', 'Prefix', 'Gateway', 'Distance', 'Metric', 'LastChange'] ['B', 'EX', '0.0.0.0/0', ['192.0.2.73'], '20', '100', '4w0d'] ['B', 'IN', '192.0.2.76/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.204/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.80/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.208/30', ['203.0.113.183'], '200', '100', '4w2d']
他のゲートウェイエントリを抽出するには、次の2つの手順でこれを行う必要があります。
次のプレフィックスエントリを開始するまで「記録」せず(追加のゲートウェイ回線の場合)、他のゲートウェイ回線を解析します。最初の処理を行うには、2つの変更を行う必要があります。まず、既存の「Record」ステートメントを削除します。次に、既存のプレフィックスエントリに一致すると、 'レコードが既存のエントリであるというステートメントを既存のステートメントの前に追加し、現在の入力行に進みます。
Routes ^ \S \S\S -> Continue.Record ^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange}
以前のプレフィックスエントリレコードを上書きせずに保存する必要があるため、新しい行は値の置換を使用しません。'Continue'ステートメントは、現在の入力行を使用して、前のデータを 'Record'した後の次のルールで再開します。これを今実行すると、出力は以前と同じであることがわかります。
ここでリストを機能させるためのステップ2は、追加のゲートウェイエントリに一致するルールを作成することです。これは最後に行きます。ここでは記録しないことに注意してください。これは、次のエントリが処理されたときにのみ発生します。EOFによって、現在のエントリが「記録」されることにも注意してください。
Routes ^ \S \S\S -> Continue.Record ^ ${Protocol} ${Type} ${Prefix}\s+via ${Gateway}\s+${Distance}/${Metric}\s+${LastChange} ^\s+via ${Gateway}
これを実行すると、デフォルトのプレフィックスのすべてのゲートウェイエントリのリストが表示されます。
FSM Table: ['Protocol', 'Type', 'Prefix', 'Gateway', 'Distance', 'Metric', 'LastChange'] ['B', 'EX', '0.0.0.0/0', ['192.0.2.73', '192.0.2.201', '192.0.2.202', '192.0.2.74'], '20', '100', '4w0d'] ['B', 'IN', '192.0.2.76/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.204/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.80/30', ['203.0.113.183'], '200', '100', '4w2d'] ['B', 'IN', '192.0.2.208/30', ['203.0.113.183'], '200', '100', '4w2d']
この例は、平均的なリストの使用法よりもいくらか複雑でした。行間に明確な区切り文字がある場合は、ここで「前方一致」スタイルを実行する必要はなく、それをレコードに使用できます。
PythonでのTextFSMの使用#
FSM自体が完全に役立つわけではありません。これは、Pythonプログラムがテキスト情報を解析するために使用することを目的としています。ここでは、Pythonスクリプト内でFSMを使用する簡単な例を紹介します。
開始するには、「routes.py」という名前の新しいファイルを作成し、それに以下を追加します。
import textfsm import sys
# テンプレートファイルを開き、それを使用して新しいTextFSMオブジェクトを初期化します。
template_file = sys.argv[1] fsm = textfsm.TextFSM(open(template_file))
# EOFまでstdinを読み取り、解析のためにこれをFSMに渡します。
input_data = sys.stdin.read() fsm_results = fsm.ParseText(input_data)
print 'Header:' print fsm.header
print 'Prefix | Gateway(s)' print '-------------------------------'
for row in fsm_results:
print '%-18.18s %s' % (row[2], ', '.join(row[3])) ```
実行可能にし、次のように実行します。
出力を調べて、FSMで「レコード」された各行がfsm_resultsリストの単一のリストタイプエントリとしてどのように表されるかに注意してください。また、行の3番目のエントリはリストタイプであり、join()で接続することに注意してください。値名のリストとしてのヘッダーも出力されます。