Skip to content

Commit

Permalink
Refactor compile_junos_data
Browse files Browse the repository at this point in the history
Add ng version of script.

Signed-off-by: Georg Pfuetzenreuter <[email protected]>
  • Loading branch information
tacerus committed Aug 17, 2023
1 parent b798eb9 commit c4495d0
Showing 1 changed file with 239 additions and 0 deletions.
239 changes: 239 additions & 0 deletions juniper_junos-formula/bin/compile_junos_data_ng.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#!/usr/bin/python3
"""
Juniper Junos Salt pillar generator
Copyright (C) 2023 SUSE LLC <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""

import argparse
import logging
import pathlib
import sys
import yaml

log = logging.getLogger(__name__)
log_choices_converter = {
'debug': logging.DEBUG,
'info': logging.INFO
}
argparser = argparse.ArgumentParser()
argparser.add_argument('--log', type=str, default='info', choices=log_choices_converter.keys())
argparser.add_argument('--in-devices', type=str, default='devices.yaml')
argparser.add_argument('--in-switching', type=str, default='switching.yaml')
argparser.add_argument('--in-backbone', type=str, default='backbone.yaml')
argparser.add_argument('--out', type=str, default='output')
args = argparser.parse_args()

infile_s = args.in_switching
infile_b = args.in_backbone
infile_d = args.in_devices
outdir = args.out

def _fail(msg):
log.error(f'{msg}, bailing out.')
sys.exit(1)

def gather(devices):
core = []
aggregation = []
access = []

for switch, config in devices.get('switches', {}).items():
role = config.get('role')
if role == 'core':
core.append(switch)
elif role == 'aggregation':
aggregation.append(switch)
elif role == 'access':
access.append(switch)
else:
_fail(f'Illegal switch role "{role}" in device {switch}')

log.debug(f'Core switches: {core}')
log.debug(f'Aggregation switches: {aggregation}')
log.debug(f'Access switches: {access}')

return core, aggregation, access

def generate(data, devices):
global_data = data.get('global', {})
port_groups = data.get('port_groups', {})
ignore_ports = global_data.get('ignore_ports', [])

big_pillar = {}

core, aggregation, access = gather(devices)

small_pillar = {
device: {
'vlans': {},
'interfaces': {},
'ignore': {'interfaces': ignore_ports}
} for device in core + aggregation + access
}


# skip global ignore ports for devices
def create_interface(interface, small_interfaces):
if interface in small_interfaces:
log.debug(f'Interface {interface} is already in pillar')
else:
small_interfaces[interface] = {
'units': {
0: {
'vlan': {'ids': []}
}
}
}

def compile_devices():
for device, d_config in data.get('devices', {}).items():

if device in small_pillar:
log.debug(f'Processing device {device}')
else:
log.warning(f'Ignoring configuration for unknown device {device}')
continue

for interface, i_config in d_config.get('interfaces', {}).items():
if interface in small_pillar[device]['ignore']['interfaces']:
_fail(f'Attempted to configure interface {interface}, but it is set to be ignored. This should not happen?')

small_interfaces = small_pillar[device]['interfaces']

create_interface(interface, small_interfaces)

small_if = small_interfaces[interface]
small_u0 = small_if['units'][0]

if 'description' in i_config:
small_if['description'] = i_config['description']

if 'port_group' in i_config:
group = i_config['port_group']

if not group in port_groups:
port_groups[group] = {}

if not device in port_groups[group]:
port_groups[group][device] = []

port_groups[group][device].append(interface)

if 'ae' in i_config:
if interface.startswith('ae'):
log.debug(f'Processing ae on interface {interface}')
ae_config = i_config['ae']

if not 'ae' in small_if:
small_if['ae'] = {}

small_ae = small_if['ae']

for ae in ['lacp', 'mc']:
if ae in ae_config:
log.debug(f'Processing {ae} on interface {interface}')
if not ae in small_ae:
small_ae[ae] = {}

small_ae = small_ae[ae]

for l_key, l_value in ae_config[ae].items():
small_ae.update({l_key: l_value})
else:
log.warning(f'Ignoring ae configuration on non-ae interface {interface}')

if 'lacp' in i_config:
log.debug(f'Processing LAG on interface {interface}')
# maybe change lacp to lag in the formula pillar, it makes more sense as a word for 802.3ad ?
small_if['lacp'] = i_config['lacp']

if 'vlan' in i_config:
log.debug(f'Processing VLAN on interface {interface}')
vlan_config = i_config['vlan']

small_vlan = small_u0['vlan']

if 'type' in vlan_config and 'ids' in vlan_config:
small_vlan.update({
'type': vlan_config['type'],
'ids': vlan_config['ids']
})
else:
log.warning(f'Ignoring incomplete VLAN configuration on interface {interface}')

if 'mtu' in i_config:
log.debug(f'Processing MTU on interface {interface}')
small_if.update({'mtu': i_config['mtu']})

def compile_vlans():
for vlan, vlan_config in data.get('vlans', {}).items():
v_id = vlan_config.get('id')
v_description = vlan_config.get('description')

log.debug(f'Processing VLAN {vlan} with ID {v_id}')

for group in vlan_config.get('groups', []):
log.debug(f'Processing group: {group}')

if group in port_groups:
for device, d_members in port_groups[group].items():
print(device)
print(d_members)
#g_description = group_config.get('description')

#if v_id in small_pillar[group]

small_device = small_pillar[device]
small_vlans = small_device['vlans']
small_ignores = small_device['ignore']['interfaces']
small_interfaces = small_device['interfaces']

print(d_members)

if not vlan in small_vlans:
small_vlans[vlan] = {
'description': v_description,
'id': v_id
}

for interface in d_members:
if interface in small_ignores:
_fail(f'Attempted to configure interface {interface}, but it is set to be ignored. This should not happen?')

create_interface(interface, small_interfaces)

tagged = small_pillar[device]['interfaces'][interface]['units'][0]['vlan']['ids']
if v_id not in tagged:
tagged.append(v_id)

compile_devices()
compile_vlans()

big_pillar.update(small_pillar)

return big_pillar

with open('sample-input.yaml', 'r') as fh:
data = yaml.safe_load(fh)

if __name__ == '__main__':
log = logging.getLogger()
log.setLevel(log_choices_converter[args.log])
log.addHandler(logging.StreamHandler(sys.stdout))
log.debug(args)
out = generate(data, {'switches': {'PRG2-IBS-CORE-H02-01': {'role': 'access'}, 'FOO': {'role': 'access'}}})
print(out)

0 comments on commit c4495d0

Please sign in to comment.