diff --git a/confluent_client/bin/l2traceroute b/confluent_client/bin/l2traceroute index 7b9ad4ac..e8f9705e 100755 --- a/confluent_client/bin/l2traceroute +++ b/confluent_client/bin/l2traceroute @@ -41,38 +41,44 @@ argparser.add_option('-i', '--interface', type='str', help='interface to check path against for the start node') argparser.add_option('-e', '--eface', type='str', help='interface to check path against for the end node') +argparser.add_option('-c', '--cumulus', action="store_true", dest="cumulus", + help='return layer 2 route through cumulus switches only') (options, args) = argparser.parse_args() +try: + start_node = args[0] + end_node = args[1] + interface = options.interface + eface = options.eface +except IndexError: + argparser.print_help() + sys.exit(1) session = client.Command() def get_neighbors(switch): switch_neigbors = [] - url = 'networking/neighbors/by-switch/{0}/by-peername/'.format(switch) + url = '/networking/neighbors/by-switch/{0}/by-peername/'.format(switch) for neighbor in session.read(url): - if neighbor['item']['href'].startswith('switch'): - switch = neighbor['item']['href'].strip('/') + switch = neighbor['item']['href'].strip('/') + if switch in all_switches: switch_neigbors.append(switch) return switch_neigbors - - def find_path(start, end, path=[]): path = path + [start] if start == end: return path # If start and end are the same, return the path for node in get_neighbors(start): - if node not in path and node.startswith('switch'): + if node not in path: new_path = find_path(node, end, path) if new_path: return new_path # If a path is found, return it return None # If no path is found, return None - - def is_cumulus(switch): try: read_attrib = subprocess.check_output(['nodeattrib', switch, 'hardwaremanagement.method']) @@ -92,11 +98,16 @@ def is_cumulus(switch): def host_to_switch(node, interface=None): # first check the the node config to see what switches are connected # if host is in rhel can use nmstate package - cummulus_switches = [] + if node in all_switches: + return [node] + switches = [] netarg = 'net.*.switch' if interface: netarg = 'net.{0}.switch'.format(interface) - read_attrib = subprocess.check_output(['nodeattrib', node, netarg]) + try: + read_attrib = subprocess.check_output(['nodeattrib', node, netarg]) + except subprocess.CalledProcessError: + return False for attribs in read_attrib.decode('utf-8').split('\n'): attrib = attribs.split(':') try: @@ -105,18 +116,11 @@ def host_to_switch(node, interface=None): except IndexError: continue switch = attrib[2].strip() - if is_cumulus(switch): - cummulus_switches.append(switch) - return cummulus_switches - -try: - start_node = args[0] - end_node = args[1] - interface = options.interface - eface = options.eface -except IndexError: - argparser.print_help() - sys.exit(1) + if is_cumulus(switch) and options.cumulus: + switches.append(switch) + else: + switches.append(switch) + return switches def path_between_nodes(start_switches, end_switches): for start_switch in start_switches: @@ -129,7 +133,17 @@ def path_between_nodes(start_switches, end_switches): return path else: return 'No path found' - + + +all_switches = [] +for res in session.read('/networking/neighbors/by-switch/'): + if 'error' in res: + sys.stderr.write(res['error'] + '\n') + exitcode = 1 + else: + switch = (res['item']['href'].replace('/', '')) + all_switches.append(switch) + end_nodeslist = [] nodelist = '/noderange/{0}/nodes/'.format(end_node) for res in session.read(nodelist): @@ -144,9 +158,14 @@ start_switches = host_to_switch(start_node, interface) for end_node in end_nodeslist: if end_node: end_switches = host_to_switch(end_node, eface) + if not end_switches: + print('Error: net.{0}.switch attribute is not valid') + continue path = path_between_nodes(start_switches, end_switches) print(f'{start_node} to {end_node}: {path}') +# TODO dont put switches that are connected through management interfaces. + diff --git a/confluent_client/doc/man/l2traceroute.ronn b/confluent_client/doc/man/l2traceroute.ronn index 7e660094..16318567 100644 --- a/confluent_client/doc/man/l2traceroute.ronn +++ b/confluent_client/doc/man/l2traceroute.ronn @@ -7,7 +7,9 @@ l2traceroute(8) -- returns the layer 2 route through an Ethernet network managed **l2traceroute** is a command that returns the layer 2 route for the configered interfaces in nodeattrib. It can also be used with the -i and -e options to check against specific interfaces on the endpoints. -Note the net..switch attributes have to be set on the end points + +## PREREQUISITES +**l2traceroute** the net..switch attributes have to be set on the end points if endpoint is not a switch ## OPTIONS @@ -15,6 +17,8 @@ Note the net..switch attributes have to be set on the end points interface to check against for the second end point * ` -i` INTERFACE, --interface=INTERFACE interface to check against for the first end point +* ` -c` CUMULUS, --cumulus=CUMULUS + return layer 2 route through cumulus switches only * `-h`, `--help`: Show help message and exit