Parsers¶
Parsers are responsible for mapping native configuration/show_commands to a YANG model.
Special actions¶
Most actions depend on the parser you are using, however, some are common to all of them:
unnecessary¶
This makes the parser skip the field and continue processing the tree.
not_implemented¶
This makes the parser stop processing the tree underneath this value. For example:
field_1:
process: unnecessary
field_2:
process: not_implemented
subfield_1:
process: ...
subfield_2:
process: ...
field_3:
...
The not_implemented
action will stop the parser from processing subfield_1
and subfield_2
and move directly onto field_3
.
gate¶
Works like not_implemented
but accepts a condition. For example:
protocols:
protocol:
bgp:
_process:
- mode: gate
when: "{{ protocol_key != 'bgp bgp' }}"
global:
...
The snippet above will only process the bgp
subtree if the condition is not met.
Special fields¶
When parsing attributes, some fields may depend on the parser you are using but some will be available regardless. Some may be even be mandatory.
mode¶
Mandatory: Yes
Description: Which parsing/translation action to use for this particular field.
Example: Parse the description field with a simple regular expression:
_process: - mode: search regexp: "description (?P<value>.*)" from: "{{ bookmarks.interface[interface_key] }}"
when¶
Mandatory: No
Description: The evaluation of this field will determine if the action is executed or skipped. This action is probably not very useful when parsing but it’s available if you need it.
Example: Configure
switchport
on IOS devices only if the interface is not a Loopback or a Management interface:ipv4: _process: unnecessary config: _process: unnecessary enabled: _process: - mode: element value: " no switchport\n" negate: " switchport\n" in: "interface.{{ interface_key }}" when: "{{ model and interface_key[0:4] not in ['Mana', 'Loop'] }}"
from¶
Mandatory: Yes
Description: Configuration to read. In combination with
bookmarks
provides the content we are operating with.Example: Get IP addresses from both both interfaces and subinterfaces:
address: _process: - mode: xpath xpath: "family/inet/address" key: name from: "{{ bookmarks['parent'] }}"
Special Variables¶
keys¶
When traversing lists, you will have all the relevant keys for the object available, including on nested
lists. Let’s see it with an example, let’s say we are currently parsing
interfaces/interface["et1"]/subinterfaces/subinterface["0"].ipv4.addresses.address["10.0.0.1"]
.
At this particular point you will have the following keys available:
- address_key -
10.0.0.1
- subinterface_key -
0
- interface_key -
et1
- parent_key -
0
When a list is traversed you will always have available a key with name $(attribute)_key
. In
addition, you will have parent_key
as the key of the immediate parent object. In the example
above, parent_key
will correspond to 0
as it’s the immediate parent of the address object.
bookmarks¶
Bookmarks are points of interest in the configuration. Usually, you will be gathering blocks of
configurations and parsing on those but sometimes, the configuration you need might be somewhere
else. For those cases, you will be able to access those with the bookmarks. Using the same example
as before,
interfaces/interface["et1"]/subinterfaces/subinterface["0"].ipv4.addresses.address["10.0.0.1"]
,
you will have the following bookmarks:
bookmarks.interfaces
- The root of the configurationbookmarks.interface["et1"]
- The block of configuration that corresponds to the interfaceet1
bookmarks.subinterface["0"]
- The block of configuration that corresponds to the subinterface0
ofet1
.bookmarks.address["10.0.0.1"]
- The block of configuration for the address belonging to the subinterface.bookmarks.parent
- The block of configuration for the immediate parent, in this case, the subinterface0
.
Note you can use keys instead and do bookmarks.subinterface[parent_key]
or
bookmarks.subinterface[subinterface_key]
.
extra_vars¶
Some actions let’s you provide additional information for later use. Those will be stored on the
extra_vars
dictionary. For example:
address:
_process:
- mode: block
regexp: "(?P<block>ip address (?P<key>(?P<ip>.*))\\/(?P<prefix>\\d+))(?P<secondary> secondary)*"
from: "{{ bookmarks['parent'] }}"
config:
_process: unnecessary
ip:
_process:
- mode: value
value: "{{ extra_vars.ip }}"
The first regexp captures a bunch of vars that later can be used by just reading them from
extra_Vars
.
Metadata¶
The metadata tells the profile how to process that module and how to get the necessary data from the device. For example:
---
metadata:
parser: XMLParser
execute:
- method: _rpc
args: []
kwargs:
get: "<get-configuration/>"
- execute is a list of calls to do to from the device to extract the data.
- method is the method from the device to call.
- args are the numbered/ordered arguments for the method
- kwargs are the keyword arguments for the method
In addition, some methods like parse_config
and parse_state
may have mechanisms to pass the
information needed to the parser instead of relying on a live device to obtain it. For parsers, you
will just have to pass a string with the same information the profile is trying to gather.