guides:user:command_parsing_templates
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| guides:user:command_parsing_templates [2019/12/23 09:23] – ↷ Links adapted because of a move operation yspeerte | guides:user:command_parsing_templates [2024/07/03 12:31] (current) – external edit 127.0.0.1 | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| + | ==== Command Parsing Template Syntax ==== | ||
| + | Command parsing templates parse the result from a command to a node, and extract variables from that output which are used in Scenarios. | ||
| + | |||
| + | The scenario command is [[menu: | ||
| + | |||
| + | A tool to assist in testing the command parser can be found at [[menu: | ||
| + | |||
| + | When referred to output in the examples, it is the same output you'll see when using the parsing tester. | ||
| + | |||
| + | |||
| + | ==== Text parsing syntax ==== | ||
| + | The text parsing syntax is described below, followed by the table parsing syntax. | ||
| + | |||
| + | Each of the capabilities is described using examples. | ||
| + | |||
| + | |||
| + | === Capabilities === | ||
| + | |||
| + | |||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * [[guides: | ||
| + | * |*| ignoring anything else on the line. | ||
| + | |||
| + | |||
| + | === Variable extraction === | ||
| + | |||
| + | A few examples on how to use this. Below is the output given for a Cisco Node with the command show version. | ||
| + | |||
| + | Let's parse this output and extract the following information: | ||
| + | | ||
| + | * software version | ||
| + | * hardware | ||
| + | * Base mac address | ||
| + | * serial number | ||
| + | |||
| + | < | ||
| + | SW1#show version | ||
| + | Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), | ||
| + | Technical Support: http:// | ||
| + | Copyright (c) 1986-2013 by Cisco Systems, Inc. | ||
| + | Compiled Wed 26-Jun-13 02:49 by mnguyen | ||
| + | |||
| + | ROM: Bootstrap program is C2960 boot loader | ||
| + | BOOTLDR: C2960 Boot Loader (C2960-HBOOT-M) Version 12.2(25r)FX, | ||
| + | |||
| + | Switch uptime is 39 minutes | ||
| + | System returned to ROM by power-on | ||
| + | System image file is " | ||
| + | |||
| + | This product contains cryptographic features and is subject to United | ||
| + | .... | ||
| + | |||
| + | cisco WS-C2960-24TT-L (PowerPC405) processor (revision B0) with 65536K bytes of memory. | ||
| + | Processor board ID FOC1010X104 | ||
| + | Last reset from power-on | ||
| + | 1 Virtual Ethernet interface | ||
| + | 24 FastEthernet interfaces | ||
| + | 2 Gigabit Ethernet interfaces | ||
| + | The password-recovery mechanism is enabled. | ||
| + | |||
| + | 64K bytes of flash-simulated non-volatile configuration memory. | ||
| + | Base ethernet MAC Address : 00: | ||
| + | Motherboard assembly number : 73-10390-03 | ||
| + | Power supply part number : 341-0097-02 | ||
| + | Motherboard serial number : FOC10093R12 | ||
| + | Power supply serial number : AZS1007032H | ||
| + | Model revision number : B0 | ||
| + | Motherboard revision number : B0 | ||
| + | Model number : WS-C2960-24TT-L | ||
| + | System serial number : FOC1010X104 | ||
| + | Top Assembly Part Number : 800-27221-02 | ||
| + | Top Assembly Revision Number : A0 | ||
| + | Version ID : V02 | ||
| + | CLEI Code Number : COM3L00BRA | ||
| + | Hardware Board Revision Number : 0x01 | ||
| + | |||
| + | |||
| + | Switch Ports Model SW Version SW Image | ||
| + | ------ ----- ----- ---------- ---------- | ||
| + | * 1 26 WS-C2960-24TT-L 15.0(2)SE4 C2960-LANBASEK9-M | ||
| + | |||
| + | |||
| + | Configuration register is 0xF | ||
| + | </ | ||
| + | |||
| + | The parsing template will look like: | ||
| + | |||
| + | < | ||
| + | Cisco IOS Software, < | ||
| + | cisco < | ||
| + | Base ethernet MAC Address : < | ||
| + | Motherboard serial number : < | ||
| + | </ | ||
| + | |||
| + | Normal text is an exact match on the command output. Some variables are temporary, which we will not use, but can be variable depending on the hardware, like < | ||
| + | |||
| + | The output of the parsing is: | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | |||
| + | If you would want to ' | ||
| + | < | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | === Headers === | ||
| + | |||
| + | |||
| + | Multiple blocks with the same text and variables. Here is how to break them up in sections: | ||
| + | |||
| + | < | ||
| + | # This template parses command results like this: | ||
| + | # Current Boot Variables: | ||
| + | # | ||
| + | # | ||
| + | # kickstart variable = bootflash:/ | ||
| + | # system variable = bootflash:/ | ||
| + | # Boot POAP Disabled | ||
| + | # | ||
| + | # Boot Variables on next reload: | ||
| + | # | ||
| + | # | ||
| + | # kickstart variable = bootflash:/ | ||
| + | # system variable = bootflash:/ | ||
| + | # Boot POAP Disabled | ||
| + | # | ||
| + | # To differentiate between current and future boot variables, headers are specified. | ||
| + | # Headers are denoted between []-brackets and their contents have to match a line, | ||
| + | # including all its special characters. | ||
| + | # | ||
| + | # In a scenario, you can now access the current boot system variable as follows | ||
| + | # (note that special characters ., :, [, ], @, %, <, > are not needed to avoid confusion with scenario syntax): | ||
| + | # <Current Boot Variables.current_boot_system%boot_variable> | ||
| + | [Current Boot Variables:] | ||
| + | kickstart variable = < | ||
| + | system variable = < | ||
| + | Boot POAP < | ||
| + | |||
| + | [Boot Variables on next reload:] | ||
| + | kickstart variable = < | ||
| + | system variable = < | ||
| + | Boot POAP < | ||
| + | </ | ||
| + | |||
| + | |||
| + | With the output: | ||
| + | |||
| + | < | ||
| + | [Current Boot Variables]: | < | ||
| + | |||
| + | [Boot Variables on next reload]: | < | ||
| + | </ | ||
| + | |||
| + | In this way, you can pick out the difference between the current boot variables, and the ones on next reload. The line between the squared brackets is a header. When the config parser parses a config, it looks out for blocks whose first line starts with this header. It only looks at the first line of this block, and headers can be made more specific. We allow a lot of special characters for example: spaces, colons, even newlines. All these need to be explicitly included. | ||
| + | |||
| + | |||
| + | === Keys === | ||
| + | |||
| + | Whenever you have multiple entries, like the example below has with interfaces, you will want to able to loop over this data and extract the necessary. You'll have to assign a variable as 'key, so you can extract variables based on that specific key. See below: | ||
| + | |||
| + | < | ||
| + | # Show cdp all returns an output like this: | ||
| + | # Ethernet1/1 is up | ||
| + | # CDP is operationally disabled as interface is in fex-fabric | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # Ethernet1/2 is up | ||
| + | # CDP is operationally disabled as interface is in fex-fabric | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # Ethernet1/3 is up | ||
| + | # CDP is operationally disabled as interface is in fex-fabric | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # Ethernet1/4 is up | ||
| + | # CDP is operationally disabled as interface is in fex-fabric | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # Ethernet1/5 is up | ||
| + | # CDP enabled on interface | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # Ethernet1/6 is down | ||
| + | # CDP enabled on interface | ||
| + | # Refresh time is 60 seconds | ||
| + | # Hold time is 180 seconds | ||
| + | # et cetera... | ||
| + | # | ||
| + | # To differentiate between interfaces we specify a key. If you do this, this will override any []-header | ||
| + | # in your results. In a scenario you can now call the result as follows: < | ||
| + | # | ||
| + | # The amount of spaces in the indentation in this pattern don't matter, | ||
| + | # as long as there is any kind of indentation. | ||
| + | < | ||
| + | CDP < | ||
| + | Refresh time is < | ||
| + | Hold time is < | ||
| + | </ | ||
| + | |||
| + | Output: | ||
| + | < | ||
| + | [Ethernet1/ | ||
| + | [Ethernet1/ | ||
| + | [Ethernet1/ | ||
| + | [Ethernet1/ | ||
| + | [Ethernet1/ | ||
| + | [Ethernet1/ | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Indentation === | ||
| + | |||
| + | Multiple hierarchical indentation also will be parsed. The templates need to follow the exact same indentation pattern and that will suffice. | ||
| + | |||
| + | < | ||
| + | # | ||
| + | # Ethernet1/ | ||
| + | # Dedicated Interface | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # MTU 1500 bytes, BW 10000000 Kbit, DLY 10 usec | ||
| + | # | ||
| + | # | ||
| + | # Port mode is FabricPath | ||
| + | # | ||
| + | # | ||
| + | # Input flow-control is off, output flow-control is off | ||
| + | # Rate mode is dedicated | ||
| + | # | ||
| + | # | ||
| + | # Last link flapped 3week(s) 6day(s) | ||
| + | # Last clearing of "show interface" | ||
| + | # 6 interface resets | ||
| + | # 30 seconds input rate 6944 bits/sec, 6 packets/sec | ||
| + | # 30 seconds output rate 120 bits/sec, 0 packets/sec | ||
| + | # | ||
| + | # input rate 6.42 Kbps, 6 pps; output rate 160 bps, 0 pps | ||
| + | # RX | ||
| + | # 15 unicast packets | ||
| + | # | ||
| + | # 0 jumbo packets | ||
| + | # 0 runts 0 giants | ||
| + | # 2 input error 0 short frame 0 overrun | ||
| + | # 0 watchdog | ||
| + | # 0 input with dribble | ||
| + | # 0 Rx pause | ||
| + | # TX | ||
| + | # 20825 unicast packets | ||
| + | # | ||
| + | # 0 jumbo packets | ||
| + | # 0 output error 0 collision | ||
| + | # 0 lost carrier | ||
| + | # 0 Tx pause | ||
| + | |||
| + | < | ||
| + | | ||
| + | Belongs to < | ||
| + | Hardware: < | ||
| + | Description: | ||
| + | MTU < | ||
| + | Port mode is < | ||
| + | RX | ||
| + | < | ||
| + | TX | ||
| + | < | ||
| + | </ | ||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | |||
| + | ==== Table parsing syntax ==== | ||
| + | |||
| + | === Capabilites === | ||
| + | |||
| + | * [headers], can consist of multiple lines and must include all characters to form a perfect match | ||
| + | * [[guides: | ||
| + | * %keys, to be able to identify unique entries | ||
| + | * < | ||
| + | * < | ||
| + | * < | ||
| + | * < | ||
| + | * [[guides: | ||
| + | * Any character matching % is appended to the key | ||
| + | * Any character matching 1 is appended to the first variable (excluding the key) | ||
| + | * Any character matching 2 is appended to the second variable | ||
| + | * ... et cetera | ||
| + | * Any character matching a is appended to the tenth variable | ||
| + | * Amy character matching b is appended to the eleventh variable | ||
| + | * ... et cetera | ||
| + | * Any character matching . is ignored | ||
| + | |||
| + | |||
| + | === Flexible table === | ||
| + | |||
| + | All table parsing templates start with a header, followed by a table syntax. Multiple headers and table syntaxes can be provided, multiple headers can precede a table syntax, but only one table syntax belongs to one header. An example: | ||
| + | |||
| + | < | ||
| + | # -------------------------------------------------------------------------------- | ||
| + | # Ethernet | ||
| + | # Interface | ||
| + | # -------------------------------------------------------------------------------- | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # et cetera | ||
| + | # | ||
| + | # There can be multiple tables, and each table can have headers of multiple lines. | ||
| + | # All these lines in a header can become one pattern header to recognize which table | ||
| + | # syntax is applicable. | ||
| + | # | ||
| + | # A table can be parsed as follows: its syntax is enclosed in between |-pipes. | ||
| + | # What follows is a list of variables. These will parse the table result, separated | ||
| + | # by spaces. | ||
| + | # < | ||
| + | # < | ||
| + | # < | ||
| + | # | ||
| + | [-------------------------------------------------------------------------------- | ||
| + | Ethernet | ||
| + | Interface | ||
| + | --------------------------------------------------------------------------------] | ||
| + | |< | ||
| + | |||
| + | [-------------------------------------------------------------------------------- | ||
| + | Port-channel VLAN Type Mode | ||
| + | Interface | ||
| + | --------------------------------------------------------------------------------] | ||
| + | |< | ||
| + | |||
| + | [-------------------------------------------------------------------------------- | ||
| + | Port | ||
| + | --------------------------------------------------------------------------------] | ||
| + | |< | ||
| + | |||
| + | [------------------------------------------------------------------------------- | ||
| + | Interface Secondary VLAN(Type) | ||
| + | -------------------------------------------------------------------------------] | ||
| + | |< | ||
| + | |||
| + | [-------------------------------------------------------------------------------- | ||
| + | Interface | ||
| + | --------------------------------------------------------------------------------] | ||
| + | |< | ||
| + | </ | ||
| + | |||
| + | Note how the # in the header in this case is not a comment, but part of the header. Headers have to match exactly, and if a table syntax has two headers, either one can match. | ||
| + | |||
| + | === Flexible table with indentation and ignoring lines === | ||
| + | |||
| + | With this, most tables can be parsed, even some with a weird layout. The problem with this table is that it has some rows that are just there for filler and aren't meant to be parsed. These can be ignored. | ||
| + | |||
| + | < | ||
| + | # Some tables have an unusual layout, and need a few workarounds to be parsed correctly | ||
| + | # For example the command show port-channel traffic returns something like this: | ||
| + | # ChanId | ||
| + | # ------ --------- ------- ------- ------- ------- ------- ------- | ||
| + | # | ||
| + | # | ||
| + | # ------ --------- ------- ------- ------- ------- ------- ------- | ||
| + | # 11 Eth2/ | ||
| + | # ------ --------- ------- ------- ------- ------- ------- ------- | ||
| + | # 1002 Eth100/ | ||
| + | # 1002 Eth101/ | ||
| + | # | ||
| + | # Any table row which starts indented can be parsed correctly by labelling the | ||
| + | # first variable as a garbage-one (for example <x>), and the rest of the line will parse correctly. | ||
| + | # | ||
| + | # Also to avoid parsing the dashed lines, you can put two slashes before it in the pattern. | ||
| + | # This will tell the command parser to simply ignore that line if it runs into it. | ||
| + | |||
| + | [ChanId | ||
| + | ------ --------- ------- ------- ------- ------- ------- -------] | ||
| + | |<x> < | ||
| + | //------ --------- ------- ------- ------- ------- ------- ------- | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Fixed table === | ||
| + | |||
| + | These kind of tables have a fixed starting point for each column. With could have 1 or multiple whitespaces between them, depending on the information stored. For these type of tables the following syntax is used: | ||
| + | |||
| + | < | ||
| + | # This example gives a fixed header with a dynamic value for the total number | ||
| + | # of entries, this can be ignored by only using the single line header of the table | ||
| + | # | ||
| + | # Flags: * - Adjacencies learnt on non-active FHRP router | ||
| + | # + - Adjacencies synced via CFSoE | ||
| + | # # - Adjacencies Throttled for Glean | ||
| + | # D - Static Adjacencies attached to down interface | ||
| + | # | ||
| + | # IP ARP Table for context default | ||
| + | # Total number of entries: 3 | ||
| + | # Address | ||
| + | # 192.168.60.1 | ||
| + | # 192.168.60.7 | ||
| + | # 192.168.60.50 | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | # | ||
| + | |||
| + | [Address | ||
| + | |< | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | # Some tables cannot be parsed based on separation by spaces, for example: | ||
| + | # -------------------------------------------------------------------------------- | ||
| + | # Port Name | ||
| + | # -------------------------------------------------------------------------------- | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # Eth1/ | ||
| + | # et cetera | ||
| + | # | ||
| + | # | ||
| + | # Headers can be of multiple lines. They can also directly follow each other. | ||
| + | # What this means is that the same rules should apply to both of them when a match is found. | ||
| + | # | ||
| + | |||
| + | [-------------------------------------------------------------------------------- | ||
| + | Port Name | ||
| + | --------------------------------------------------------------------------------] | ||
| + | ^< | ||
| + | %%%%%%%%%%%%%.111111111111111111.222222222.333333333.4444444.5555555.666666666666 | ||
| + | </ | ||
| + | |||
| + | |||
| + | ==== Command Scope ==== | ||
| + | |||
| + | Our command parser can handle a lot of different syntaxes, but it won't be able to parse everything. For example, if you want to parse the running configuration, | ||
| + | |||
| + | * Any table whose rows consist out of multiple lines. For example: | ||
| + | |||
| + | < | ||
| + | VLAN Name | ||
| + | ---- -------------------------------- --------- ------------------------------- | ||
| + | 1 default | ||
| + | Eth1/6, Eth1/7, Eth1/8, Eth1/9 | ||
| + | Eth1/10, Eth1/11, Eth1/12 | ||
| + | Eth1/13, Eth1/14, Eth1/15 | ||
| + | </ | ||
| + | |||
| + | * Any command that returns a very large string of text, combining any regular parseable text together with tables. It will either be just parsing tables, or text, not both. | ||
| + | * You will probably want to split or filter that using filters on the command you're using on the node itself. | ||