Make Junos-style configs searchable
mpenning opened this issue · 5 comments
Some people want ciscoconfparse to search Junos configurations... this bug tracks implementation of the feature request.
We now parse Junos configurations into Cisco IOS-style (I already hear the distant cries of "heretic")... nevertheless, if you want to see it in action, here's how I parse configs/sample_01.junos
:
>>> from ciscoconfparse import CiscoConfParse
>>> parse = CiscoConfParse('configs/sample_01.junos', syntax='junos', comment='#!')
>>> for line in parse.ioscfg:
... print line
...
!# Last commit: 2015-06-28 13:00:59 CST by mpenning
system
host-name TEST01_EX
domain-name pennington.net
domain-search [ pennington.net lab.pennington.net ]
location
country-code 001
building HQ_005
floor 1
root-authentication
encrypted-password "$1$y7ArHxKU$zUbdeLfBirgkCsKiOJ5Qa0"
name-server
172.16.3.222
login
announcement "Test Lab Switch"
class super-user
authentication
encrypted-password "$1$y7ArHxKU$zUbdeLfBirgkCsKiOJ5Qa0"
services
ssh
root-login allow
telnet
web-management
http
syslog
user *
any emergency
file messages
any notice
authorization info
file interactive-commands
interactive-commands any
ntp
boot-server time.apple.com
server 172.16.8.3
vlans
Management
vlan-id 1
interface
ge-0/0/0.0
ge-0/0/1.0
ge-0/0/2.0
ge-0/0/3.0
VLAN_FOO
vlan-id 5
vlan1
vlan-id 1
l3-interface vlan.1
vlan800
vlan-id 800
ethernet-switching-options
storm-control
interface all
interfaces
ge-0/0/0
unit 0
family ethernet-switching
port-mode access
vlan
members VLAN_FOO
ge-0/0/1
unit 0
family ethernet-switching
port-mode trunk
vlan
members all
native-vlan-id 1
vlan
unit 0
family inet
address 172.16.15.5/22
routing-options
static
route 0.0.0.0/0 next-hop 172.16.12.1
route 192.168.36.0/25 next-hop 172.16.12.1
This is a hack, to be sure... so I'm leaving the enhancement open until I get a few more details nailed down... in the mean time, if people want to experiment with searching Junos as IOS, it is here :-)
Junos Searches with find_object_branches()
Recommended: Use the find_object_branches()
method as illustrated below._
Junos Searches with find_objects_w_*()
Not Recommended: Juniper configurations are quite hierarchical... To get the interface object for a Junos interface such as ge-0/0/1
, you'd need to use something like parse.find_objects_w_parents(r'^\s*interface', r'^\s+ge-0/0/1')
, which returns the object for ge-0/0/1
in a list. Then you can iterate through for children of ge-0/0/1
as you like.
However, if you don't require the interface object itself, you can still enforce Junos interface configuration policies in python via parse.find_objects_w_child(r'^\s+ge-0/0/1', r'port-mode\saccess')
; that policy checks whether ge-0/0/1
is port-mode access
.
Hi Mike
I am trying to parse the F5 Networks configurations. Do you have a syntax ready for bigIP or any timeplan :)
currently i am getting following error on at
line 263, in __init__
config = self.convert_braces_to_ios(rgx.split(text))
line 389, in convert_braces_to_ios
line, line_offset = line_level(tmp.strip())
line 383, in line_level
raise ValueError("Could not parse: '{0}'".format(input))
ValueError: Could not parse: '} else {'
Running the code like
from ciscoconfparse import CiscoConfParse
parse = CiscoConfParse("/Users/python/lbj.junos", syntax='junos', comment='#')
for line in parse.ioscfg:
print (line)
@kthned, "} else {" should parse correctly in the latest versions... please let me know if you run into problems
Another junos-parsing example using find_object_branches()
Suppose you want to associate junos interface names with their IP addresses from this example config...
config = r"""
interfaces {
xe-0/0/0 {
unit 0 {
family inet {
address 1.1.1.6/31;
}
family inet6 {
address FD00:DEAD:CAFE:6000::4/127;
}
}
}
xe-0/0/1 {
unit 0 {
family inet {
address 2.2.2.10/31;
}
family inet6 {
address FD00:DEAD:CAFE:7903::2/64;
}
}
}
xe-0/0/2 {
mtu 9192;
unit 0 {
family inet {
address 3.3.3.14/31;
}
family inet6 {
address FD00:DEAD:CAFE:6000::26/127;
}
}
}
}
""".splitlines()
from ciscoconfparse import CiscoConfParse
parse = CiscoConfParse(config, syntax='junos', comment='#')
branchspec = (
r'interfaces',
r'^\s+\S+', # Detect any intf name...
r'^\s+unit',
r'^\s+family',
r'^\s+address',
)
for params in parse.find_object_branches(branchspec):
# Select the params with the corresponding index of the regex specified in branchspec, above...
intf_obj, intf_family_obj, addr_obj = params[1], params[3], params[4]
intf_name = intf_obj.re_match_typed('^\s+(\S+)')
intf_family = intf_family_obj.re_match_typed('\s+family\s+(inet\S*)')
addr = addr_obj.re_match_typed('^\s+address\s+(\S+)')
print("{} {} {}".format(intf_name, intf_family, addr))
When you run the script above, you will get this as output...
xe-0/0/0 inet 1.1.1.6/31
xe-0/0/0 inet6 FD00:DEAD:CAFE:6000::4/127
xe-0/0/1 inet 2.2.2.10/31
xe-0/0/1 inet6 FD00:DEAD:CAFE:7903::2/64
xe-0/0/2 inet 3.3.3.14/31
xe-0/0/2 inet6 FD00:DEAD:CAFE:6000::26/127