networktocode / netutils

Python library that is a collection of functions and objects for common network automation tasks.
https://netutils.readthedocs.io/
Other
218 stars 50 forks source link

config parser enhancements #156

Open p-sherratt opened 2 years ago

p-sherratt commented 2 years ago

Environment

Proposed Functionality

No specific functionality is proposed but can be discussed as the use cases are considered.

Use Case

Use-cases include:

The demo output below is from my own tooling based on the Lark parsing toolkit, which I can share privately but consider to be PoC quality. The ideas may be used to enhance functionality in the netutils config parser.

Example

demo.py

from copy import deepcopy
from conformer.collections import ConfigDict
from conformer.interpreters import PatchInterpreter
from conformer.parsers import IOSPatchParser
from conformer.renderers import IOSConfigRenderer

CONFIG = """
lldp run
!
interface Ethernet0
 no ip redirects
 ip unreachables
 ip proxy-arp
 !
ip access-list extended ACL-MGMT-IN
 permit icmp host 1.2.3.4 any foo
 permit tcp host 1.2.3.4 any ssh
 deny tcp any any fragments
 deny udp any any fragments
"""

CONFIG_PATCH = """
[delete]
cdp run
lldp run
service password-recovery

[delete-regex] banner .*

[replace]
ip access-list extended ACL-MGMT-IN
 permit icmp host 1.2.3.4 any echo
 permit tcp host 1.2.3.4 any ssh
 deny tcp any any fragments
 deny udp any any fragments

control-plane host
 management-interface GigabitEthernet 0/1 allow ssh https

[merge]
interface Ethernet0
 no ip redirects
 no ip unreachables
 [delete]
 ip proxy-arp
"""

def demo():
    target = ConfigDict()
    parser = IOSPatchParser()
    patcher = PatchInterpreter(target)
    renderer = IOSConfigRenderer(target)

    config_tree = parser.parse(CONFIG)
    patch_tree = parser.parse(CONFIG_PATCH)

    # Apply current config to patcher
    patcher.visit(config_tree)
    print("Current")
    print("-------")
    renderer.print(patcher.target)
    print()

    # Load config patch into patcher
    current = deepcopy(patcher.target)
    patcher.visit(patch_tree)

    print("Patched")
    print("-------")
    renderer.print(patcher.target)
    print()

    # Calculate diff between current and patched config
    diff = current.diff(patcher.target)
    print("Diff")
    print("----")
    diff.pretty_print()
    print("")

if __name__ == "__main__":
    demo()

output

Current
-------
lldp run
interface Ethernet0
 no ip redirects
 ip unreachables
 ip proxy-arp
ip access-list extended ACL-MGMT-IN
 permit icmp host 1.2.3.4 any foo
 permit tcp host 1.2.3.4 any ssh
 deny tcp any any fragments
 deny udp any any fragments

Patched
-------
no lldp run
interface Ethernet0
 no ip redirects
 no ip unreachables
 no ip proxy-arp
ip access-list extended ACL-MGMT-IN
 no permit icmp host 1.2.3.4 any foo
 permit tcp host 1.2.3.4 any ssh
 deny tcp any any fragments
 deny udp any any fragments
 permit icmp host 1.2.3.4 any echo
control-plane host
 management-interface GigabitEthernet 0/1 allow ssh https

Diff
----
no lldp run   (from line 4 column 1)
interface Ethernet0   (from line 7 column 2)
 no ip unreachables   (from line 22 column 2)
 no ip proxy-arp   (from line 24 column 2)
ip access-list extended ACL-MGMT-IN   (from line 10 column 2)
 no permit icmp host 1.2.3.4 any foo   (from line 10 column 2)
 permit icmp host 1.2.3.4 any echo   (from line 11 column 2)
control-plane host   (from line 16 column 1)
 management-interface GigabitEthernet 0/1 allow ssh https   (from line 17 column 2)
itdependsnetworks commented 2 years ago

I think this makes sense

Providing the user information about where intended changes in configuration have originated from. This would be of great help when maintaining larger configurations and a library of configuration templates.

For

Incremental/partial patch-based configuration changes, not just "big-bang" changes.
Tracking "negated" configuration items. For example if a cisco-style change is applied which under a specific interface sets "no ip proxy-arp", followed by another change to set "ip proxy-arp", there should only be a single configuration line as a result.

I think the current recommendation will be https://github.com/netdevops/hier_config