Skip to content

Commit

Permalink
Merge pull request #164 from alekshi/cisco.parser_fix
Browse files Browse the repository at this point in the history
Cisco.parser fix
  • Loading branch information
gescheit authored Nov 26, 2024
2 parents 605983c + e0cb410 commit 8382c3c
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 95 deletions.
1 change: 1 addition & 0 deletions annet/annlib/netdev/devdb/data/devdb.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"Huawei.CE.CE8800.CE8850": " CE8850",
"Huawei.CE.CE8800.CE8851": " CE8851",
"Huawei.CE.CE8800.CE8855": " CE8855",
"Huawei.CE.CE8800.CE8875": " CE8875",
"Huawei.CE.CE9800": " CE98\\d\\d",
"Huawei.CE.CE9800.CE9855": " CE9855",
"Huawei.CE.CE9800.CE9860": " CE9860",
Expand Down
59 changes: 57 additions & 2 deletions annet/annlib/tabparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import itertools
import re
from collections import OrderedDict as odict
from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Tuple, Union
from typing import TYPE_CHECKING, Any, Dict, Iterable, Optional, Tuple, Union, List

from .types import Op

Expand Down Expand Up @@ -271,8 +271,63 @@ class CiscoFormatter(BlockExitFormatter):
def __init__(self, indent=" "):
super().__init__("exit", indent)

def _split_indent(
self, line: str, indent: int, block_exit_strings: List[str]
) -> Tuple[List[str], int]:
"""
The small helper calculates indent shift based on block exit string.
If configuration line has non-default block exit string it means that
new subsection is started and indent should be increased.
If configuration line exists in list of block exit strings,
it means that subsection is finished and indent should be decreased
Args:
line: just configuration line
indent: current indent
block_exit_strings: list of previously seen block exit strings
Returns:
new indent and list of previously seen block exit strings
"""

if line.strip() in block_exit_strings:
indent -= 1
block_exit_strings.remove(line.strip())
return block_exit_strings, indent

block_exit_wrapped = [
v for v in self.block_exit(FormatterContext(current=(line.strip(), {})))
]

if not block_exit_wrapped or len(block_exit_wrapped) != 3:
return block_exit_strings, indent
if not isinstance(block_exit_wrapped[1], str):
return block_exit_strings, indent
if block_exit_wrapped[1] == self._block_exit:
return block_exit_strings, indent

indent += 1
block_exit_strings.append(block_exit_wrapped[1])
return block_exit_strings, indent

def split(self, text):
return self.split_remove_spaces(text)
additional_indent = 0
block_exit_strings = [self._block_exit]
tree = self.split_remove_spaces(text)
for i, item in enumerate(tree):
block_exit_strings, new_indent = self._split_indent(
item, additional_indent, block_exit_strings
)
tree[i] = f"{' ' * additional_indent}{item}"
additional_indent = new_indent
return tree

def block_exit(self, context: Optional[FormatterContext]) -> str:
current = context and context.row or ""

if current.startswith(("address-family")):
yield from block_wrapper("exit-address-family")
else:
yield from super().block_exit(context)


class AsrFormatter(BlockExitFormatter):
Expand Down
90 changes: 0 additions & 90 deletions annet/rulebook/cisco/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,93 +57,3 @@ def banner_login(rule, key, diff, **_):
yield (False, f"banner login {key}", None)
else:
yield from common.default(rule, key, diff)


def bgp_diff(old, new, diff_pre, _pops=(Op.AFFECTED,)):
"""
Some oder versions of Cisco IOS doesn't create subsection for address family block.
it looks like:
router bgp 65111
bgp router-id 1.1.1.1
bgp log-neighbor-changes
neighbor SPINE peer-group
!
address-family ipv4
neighbor SPINE send-community both
neighbor SPINE soft-reconfiguration inbound
neighbor SPINE route-map TOR_IMPORT_SPINE in
neighbor SPINE route-map TOR_EXPORT_SPINE out
exit-address-family
but should be
router bgp 65111
bgp router-id 1.1.1.1
bgp log-neighbor-changes
neighbor SPINE peer-group
!
address-family ipv4
neighbor SPINE send-community both
neighbor SPINE soft-reconfiguration inbound
neighbor SPINE route-map TOR_IMPORT_SPINE in
neighbor SPINE route-map TOR_EXPORT_SPINE out
exit-address-family
The diff_logic func do it before make diff.
"""
corrected_old = _create_subsections(old, "address-family")

yield from common.default_diff(corrected_old, new, diff_pre, _pops)


def _create_subsections(data: OrderedDict[str, Any], sub_section_prefix: str) -> OrderedDict[str, Any]:
"""
Reorganizes the given OrderedDict to nest commands under their respective
sub_section_prefix keys.
This function traverses the entries in the provided OrderedDict and groups
together all entries that are between keys with sub_section_prefix under those
keys as nested OrderedDicts. The reorganization keeps the order of entries
stable, only adding nesting where appropriate.
Args:
data (OrderedDict): The original configuration to be transformed.
sub_section_prefix (str): Prefix of subsection key
Returns:
OrderedDict: A new OrderedDict with nested 'address-family' sections.
"""

result = OrderedDict()
sub_section = None
temp: OrderedDict = OrderedDict()

for key, value in data.items():
# make nested loop if found nested values
if value:
fixed_value: OrderedDict[str, Any] = _create_subsections(value, sub_section_prefix)
else:
fixed_value = value
if key.startswith(sub_section_prefix):
# in case of data has already had subsections
if value:
result[key] = fixed_value
continue
# if previous subsection present save collected data from temporary dict
if sub_section:
result[sub_section] = temp
# find a new subsection and initialize new dict
sub_section = key
temp = OrderedDict()
# put found data to temporary dict
elif sub_section:
temp[key] = fixed_value
else:
result[key] = fixed_value
# if data is finished save collected data from temporary dict
if sub_section:
result[sub_section] = temp

return result
2 changes: 1 addition & 1 deletion annet/rulebook/texts/cisco.rul
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ interface */\w*Ethernet[0-9\/]+$/ %logic=common.permanent %diff_logic=cisco.
storm-control * level
spanning-tree portfast

router bgp * %diff_logic=cisco.misc.bgp_diff
router bgp
router-id
vrf *
router-id
Expand Down
7 changes: 5 additions & 2 deletions tests/annet/test_patch/cisco_bgp_address_family.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
neighbor SPINE route-map TOR_EXPORT_SPINE out
neighbor 10.1.1.11 activate
neighbor 10.2.1.11 activate
exit-address-family
after: |
router bgp 65111
bgp router-id 1.1.1.1
Expand All @@ -38,13 +39,15 @@
neighbor 10.2.1.11 activate
no neighbor 2001:DB8:1:1::11 activate
no neighbor 2001:DB8:2:1::11 activate
exit-address-family
address-family ipv6
neighbor SPINEv6 send-community both
neighbor SPINEv6 soft-reconfiguration inbound
neighbor SPINEv6 route-map TOR_IMPORT_SPINE in
neighbor SPINEv6 route-map TOR_EXPORT_SPINE out
neighbor 2001:DB8:1:1::11 activate
neighbor 2001:DB8:2:1::11 activate
exit-address-family
patch: |
conf t
router bgp 65111
Expand All @@ -56,15 +59,15 @@
address-family ipv4
no neighbor 2001:DB8:1:1::11 activate
no neighbor 2001:DB8:2:1::11 activate
exit
exit-address-family
address-family ipv6
neighbor SPINEv6 send-community both
neighbor SPINEv6 soft-reconfiguration inbound
neighbor SPINEv6 route-map TOR_IMPORT_SPINE in
neighbor SPINEv6 route-map TOR_EXPORT_SPINE out
neighbor 2001:DB8:1:1::11 activate
neighbor 2001:DB8:2:1::11 activate
exit
exit-address-family
exit
exit
copy running-config startup-config

0 comments on commit 8382c3c

Please sign in to comment.