I am parsing Junos configurations stored in text files generated by RANCID. For convenience in my dev case, some of the interesting configuration hierarchies are stored in a variable in the script.
My specific requirement is to collect the physical interface, its associated units, and each unit's associated IPv4 & IPv6 IP addresses.
ChatGPT and I have worked it to some degree but I have hit a roadblock and I'm asking for help.
The current script nests a list into a nested dict of an outer dict. Outer: interfaces_physical Middle: interfaces_unit Inner list: ips / ip_address
The script is close but duplicates entries in output. I need to more tightly bind the physical, unit, and addresses with each other to prevent the duplication. I believe this is just a loop formatting issue, but I'm out of my depth. I appreciate any help you can offer.
Example Broken Output:
Interfaces {
xe-0/0/8 {
unit 4 {
address 1.1.1.0/31;
xe-0/0/8 {
unit 4 {
address 2.2.2.1/25;
Interfaces {
irb {
unit 10 {
address 2.2.2.1/25;
irb {
unit 10 {
address 5.5.5.1/26;
irb {
unit 10 {
address 3.3.3.1/26;
#!/usr/bin/env python3
import re
config = """
interfaces {
xe-0/0/8 {
description "AGG BACKBONE: to asdf.fdas xe-0/0/17 | 10GE-13434 [PENDING]";
vlan-tagging;
mtu 9192;
encapsulation flexible-ethernet-services;
unit 4 {
description "NAT64 to asdf.fdas xe-0/0/17 | NW | VLAN-3435 [PENDING]";
vlan-id 4;
family inet {
mtu 9000;
address 1.1.1.0/31;
}
}
}
irb {
unit 10 {
description "RACKLAN: DENV Racklan | VLAN-03827";
family inet {
address 2.2.2.1/25;
}
}
unit 11 {
description "Management | MANAGEMENT | MGMT | @SID@ [NO-MONITOR]";
family inet {
mtu 1500;
address 5.5.5.1/26;
}
}
unit 60 {
description "Service Gateway | 1G-Service | default | @SID@ [NO-MONITOR]";
family inet {
address 3.3.3.1/26;
}
}
unit 3903 {
description "TIC_3903 | NWAVE | VLAN-04251";
family inet {
mtu 9000;
filter {
input SAMPLE_AND_MIRROR_OUT_XCPT;
output SAMPLE_AND_MIRROR_OUT_XCPT;
}
address 4.4.4.2/31;
}
family inet6 {
inactive: filter {
input MIRROR6;
output MIRROR6;
}
address 2610:0:0:1::1/64;
}
}
}
lo0 {
unit 0 {
family inet {
filter {
input 20180626_LOOPBACK_IPV4;
}
address 5.5.5.1/32;
}
family iso {
address 49.0002.0050.0500.5001.00;
}
family inet6 {
filter {
input 20161130_LOOPBACK_IPV6;
}
address 2610:0:0::30/128;
}
}
ae2 {
apply-groups INTERFACE_LAG_DEFAULTS;
description "asdf.asfd | LAG-04250";
flexible-vlan-tagging;
mtu 9192;
encapsulation flexible-ethernet-services;
unit 3903 {
description "qwr.rewq | 3903 | VLAN-04251";
encapsulation vlan-bridge;
vlan-id 3903;
}
unit 3904 {
description "qwer.rewq | 3904 | VLAN-04252";
encapsulation vlan-bridge;
vlan-id 3904;
}
}
ae3 {
description "qwer.zxcv | LAG-04672";
mtu 9192;
unit 0 {
description "dfgh.asdf | default VLAN-04673";
family inet {
mtu 9000;
address 10.174.4.21/30 {
arp 10.174.4.22 mac 00:01:02:03:04:08;
}
}
family inet6 {
mtu 9000;
address fc00::3/127 {
ndp fc00::2 mac 00:01:02:03:04:08;
}
}
}
}
"""
interfaces_physical = re.compile(r"^\ {4}[gaxeli]r?[oetb].*$\n", re.MULTILINE)
interfaces_unit = re.compile(r"^\ {8}unit.*$\n", re.MULTILINE)
ip_address = re.compile(r"(^\ {16}address.*$\n)", re.MULTILINE)
interfaces = {}
for match in interfaces_physical.finditer(config):
interface = match.group()
interfaces[interface] = {}
for match in interfaces_unit.finditer(config, match.start()):
unit = match.group()
ips = [m.group(1) for m in ip_address.finditer(config, match.start())]
interfaces[interface][unit] = ips
for k1, v1 in interfaces.items():
for k2, v2 in v1.items():
for ipaddr in v2:
print("{}{}{}".format(k1, k2, ipaddr))
print("Interfaces {")