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:31] – ↷ 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. |