netdevops / hier_config

Hierarchical Configuration
MIT License
126 stars 24 forks source link

Multi-level diff support #117

Closed mpenning closed 9 months ago

mpenning commented 9 months ago

Thank you for a great diff library! ciscoconfparse2 uses hier_config for diffs, but multi-level diffs are broken as of version 2.2.3.

This is an example from ciscoconfparse2 issue # 4

from ciscoconfparse2 import Diff

running = """
policy-map type inspect pm-self-to-accesspoints
  class type inspect cm-self-to-accesspoints
    inspect
  class type inspect self-to-any-dhcp
    pass
  class class-default
    drop
"""
generated = """
policy-map type inspect pm-self-to-accesspoints
  class type inspect self-to-any-dhcp
    pass
  class type inspect cm-self-to-accesspoints
    inspect
  class class-default
    drop
"""
diff = Diff(old_config=running, new_config=generated)
for line in diff.get_diff():
    print(line)

The example above prints nothing even though the configurations are different. Single-level diffs work fine, so this seems to be an issue with hier_config itself.

jtdub commented 9 months ago

Hi @mpenning -- Thanks for the Issue. It took a lot of staring at the configs, but they are indeed the same configurations. The only difference is the class types are in different orders. hier_config. From a hier_config perspective, "olicy-map type inspect pm-self-to-accesspoints" is a parent object and "class type inspect cm-self-to-accesspoints" is a child object of the parent.

I can see scenarios where the order of a policy-map can be important. Out of the box hier_config probably isn't going to work in that scenario. You would likely need a custom hier_config module to enforce the ordering of the object.

Here's how hier_config views the parent / child relationship.

>>> host.running_config.children
[HConfigChild(HConfig, policy-map type inspect pm-self-to-accesspoints)]
>>> host.generated_config.children
[HConfigChild(HConfig, policy-map type inspect pm-self-to-accesspoints)]
>>> 
>>> 
>>> r_pm = host.running_config.get_child("startswith", "policy-map")
>>> g_pm = host.generated_config.get_child("startswith", "policy-map")
>>> 
>>> r_pm
HConfigChild(HConfig, policy-map type inspect pm-self-to-accesspoints)
>>> r_pm.children
[HConfigChild(HConfigChild, class type inspect cm-self-to-accesspoints), HConfigChild(HConfigChild, class type inspect self-to-any-dhcp), HConfigChild(HConfigChild, class class-default)]
>>> g_pm.children
[HConfigChild(HConfigChild, class type inspect self-to-any-dhcp), HConfigChild(HConfigChild, class type inspect cm-self-to-accesspoints), HConfigChild(HConfigChild, class class-default)]
mpenning commented 9 months ago

Out of the box hier_config probably isn't going to work in that scenario. You would likely need a custom hier_config module to enforce the ordering of the object.

I can live with this.