#! /usr/bin/python -u
# A simple script to parse /proc/net/bonding and print sorted JSON list of all
# bonds and their attributes. Each bond array contains bond_port_list that
# contains a list of bond slave arrays.
import glob, json, pprint, syslog
def get_bond_attrs():
    mainArray = {}
    mainArray['bond_list'] = []
    procnetbonding = '/proc/net/bonding/'
    syspath = '/sys/class/net/'
    # loop over the bonds under /proc/net/bonding
    for bondname in [b.split('/')[4] for b in glob.glob('%s*'%procnetbonding)]:
        bondportArray = None
        details = None
        bondArray = {}
        bondArray['ifname'] = bondname
        # create a list of bond ports 
        bondArray['bond_port_list'] = []
        bondArray['address'] = open('%s%s/address' % (syspath, bondname),
                                    'r').read().strip()
        bondArray['ifindex'] = int(open('%s%s/ifindex' % (syspath, bondname),
                                        'r').read().strip())
        # parse the /proc/net/bonding file
        procnetfile = '%s%s' % (procnetbonding, bondname)
        procnetbondlines = open(procnetfile, 'r').read().split('\n')
        for line in procnetbondlines:
            line = line.strip()
            if line and ':' in line:
                # find the first colon (since MACs have many colons)
                colonindex = line.find(':')
                name = line[0:colonindex].strip()
                value = line[colonindex+1:].strip()
                if name == 'Slave Interface':
                    # we are in a bond port, start a new ifname
                    bondport = value
                    bondportArray = {}
                    # we have a sub category of actor or partner
                    details = None
                    bondportArray.setdefault('ifname', value)
                    bondportArray.setdefault('masterifindex', bondArray['ifindex'])
                    bondportArray['ifindex'] = int(open('%s%s/ifindex' % \
                                        (syspath, bondport), 'r').read().strip())
                    bondportArray['address'] = open('%s%s/address' % \
                                        (syspath, bondport), 'r').read().strip()
                    # grab the number of ports from the master and add it to the port
                    bondportArray.setdefault('number_of_ports',
                                             bondArray.get('number_of_ports'))
                    bondArray['bond_port_list'].append(bondportArray)
                if 'details actor' in line:
                    details = 'actor_'
                elif 'details partner' in line:
                    details = 'partner_'
                if details:
                    # add in the details sub category
                    name = '%s%s' % (details, name)
                name = name.lower().replace(' ', '_')
                if bondportArray:
                    # we are in a bond port, add to the list
                    bondportArray.setdefault(name, value)
                else:
                    # we are still in the bond master section
                    bondArray.setdefault(name, value)

        # make sure the bond port list is sorted
        bondArray['bond_port_list'].sort(key=lambda x: x['ifindex'])
        mainArray['bond_list'].append(bondArray)
    # make sure the bond list in the main array is sorted by ifindex
    mainArray['bond_list'].sort(key=lambda x: x['ifindex'])
    return mainArray

try:
    print json.dumps(get_bond_attrs(), indent=4, sort_keys=True)
except Exception as e:
    syslog.syslog('Error: exception %s'%e)
