Fix for issue with ip detection sometimes breaking.

This commit is contained in:
Antoine Weill--Duflos
2024-11-24 15:55:35 -05:00
parent 43521037cb
commit 96be21fd68

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
__author__ = "ffsb" __author__ = "ffsb"
__version__ = "0.1" #initial __version__ = "0.1" # initial
__version__ = "0.2" # added logic to retry omada api call once as it seems to sometimes fail for some reasons, and error handling logic... __version__ = "0.2" # added logic to retry omada api call once as it seems to sometimes fail for some reasons, and error handling logic...
__version__ = "0.3" # split devices API calls to allow multithreading but had to stop due to concurency issues. __version__ = "0.3" # split devices API calls to allow multithreading but had to stop due to concurency issues.
__version__ = "0.6" # found issue with multithreading - my omada calls redirect stdout which gets clubbered by normal stdout... not sure how to fix for now... __version__ = "0.6" # found issue with multithreading - my omada calls redirect stdout which gets clubbered by normal stdout... not sure how to fix for now...
@@ -8,6 +8,7 @@ __version__ = "0.7" # avoid updating omada sdn client name when it is the MAC,
__version__ = "1.0" # fixed the timzone mylog issue by resetting the tz value at the begining of the script... I suspect it doesn't inherit the tz from the main. __version__ = "1.0" # fixed the timzone mylog issue by resetting the tz value at the begining of the script... I suspect it doesn't inherit the tz from the main.
__version__ = "1.1" # added logic to handle gracefully a failure of omada devices so it won't try to populate uplinks on non-existent switches and AP. __version__ = "1.1" # added logic to handle gracefully a failure of omada devices so it won't try to populate uplinks on non-existent switches and AP.
__version__ = "1.2" # finally got multiprocessing to work to parse devices AND to update names! yeah! __version__ = "1.2" # finally got multiprocessing to work to parse devices AND to update names! yeah!
__version__ = "1.3" # fix detection of the default gateway IP address that would pick loopback address instead of the actual gateway.
# query OMADA SDN to populate NetAlertX witch omada switches, access points, clients. # query OMADA SDN to populate NetAlertX witch omada switches, access points, clients.
@@ -29,12 +30,13 @@ import importlib.util
import time import time
import io import io
import re import re
#import concurrent.futures
# import concurrent.futures
import subprocess import subprocess
import multiprocessing import multiprocessing
#import netifaces # import netifaces
# Define the installation path and extend the system path for plugin imports # Define the installation path and extend the system path for plugin imports
INSTALL_PATH = "/app" INSTALL_PATH = "/app"
@@ -48,21 +50,22 @@ from helper import timeNowTZ, get_setting_value
from notification import write_notification from notification import write_notification
from pytz import timezone from pytz import timezone
import conf import conf
conf.tz = timezone(get_setting_value('TIMEZONE'))
conf.tz = timezone(get_setting_value("TIMEZONE"))
PARALLELISM = 4 PARALLELISM = 4
# Define the current path and log file paths # Define the current path and log file paths
CUR_PATH = str(pathlib.Path(__file__).parent.resolve()) CUR_PATH = str(pathlib.Path(__file__).parent.resolve())
LOG_FILE = os.path.join(CUR_PATH, 'script.log') LOG_FILE = os.path.join(CUR_PATH, "script.log")
RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log') RESULT_FILE = os.path.join(CUR_PATH, "last_result.log")
OMADA_API_RETURN_FILE = os.path.join(CUR_PATH, 'omada_api_return') OMADA_API_RETURN_FILE = os.path.join(CUR_PATH, "omada_api_return")
# Initialize the Plugin obj output file # Initialize the Plugin obj output file
plugin_objects = Plugin_Objects(RESULT_FILE) plugin_objects = Plugin_Objects(RESULT_FILE)
# #
# sample target output: # sample target output:
# 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, 5 TYPE # 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, 5 TYPE
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', '17', '40-AE-30-A5-A7-50, 'Switch']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', '17', '40-AE-30-A5-A7-50, 'Switch']"
# Constants for array indices # Constants for array indices
MAC, IP, NAME, SWITCH_AP, PORT_SSID, TYPE = range(6) MAC, IP, NAME, SWITCH_AP, PORT_SSID, TYPE = range(6)
@@ -70,59 +73,72 @@ MAC, IP, NAME, SWITCH_AP, PORT_SSID, TYPE = range(6)
# sample omada devices input format: # sample omada devices input format:
# #
# 0.MAC 1.IP 2.type 3.status 4.name 5.model # 0.MAC 1.IP 2.type 3.status 4.name 5.model
#40-AE-30-A5-A7-50 192.168.0.11 ap CONNECTED office_Access_point EAP773(US) v1.0 # 40-AE-30-A5-A7-50 192.168.0.11 ap CONNECTED office_Access_point EAP773(US) v1.0
#B0-95-75-46-0C-39 192.168.0.4 switch CONNECTED pantry12 T1600G-52PS v4.0 # B0-95-75-46-0C-39 192.168.0.4 switch CONNECTED pantry12 T1600G-52PS v4.0
dMAC, dIP, dTYPE, dSTATUS, dNAME, dMODEL = range(6) dMAC, dIP, dTYPE, dSTATUS, dNAME, dMODEL = range(6)
# sample omada clients input format: # sample omada clients input format:
# 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, # 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID,
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', 'myssid_name2', '(office_Access_point)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', 'myssid_name2', '(office_Access_point)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-01', '192.168.0.153', 'frontyard_ESP_29E753', 'pantry12', '(48)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-01', '192.168.0.153', 'frontyard_ESP_29E753', 'pantry12', '(48)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-02', '192.168.0.1', 'bastion', 'office24', '(23)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-02', '192.168.0.1', 'bastion', 'office24', '(23)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-03', '192.168.0.226', 'brick', 'myssid_name3', '(office_Access_point)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-03', '192.168.0.226', 'brick', 'myssid_name3', '(office_Access_point)']"
cMAC, cIP, cNAME, cSWITCH_AP, cPORT_SSID = range(5) cMAC, cIP, cNAME, cSWITCH_AP, cPORT_SSID = range(5)
OMDLOGLEVEL = 'debug' OMDLOGLEVEL = "debug"
pluginName = 'OMDSDN' pluginName = "OMDSDN"
# #
# translate MAC address from standard ieee model to ietf draft # translate MAC address from standard ieee model to ietf draft
# AA-BB-CC-DD-EE-FF to aa:bb:cc:dd:ee:ff # AA-BB-CC-DD-EE-FF to aa:bb:cc:dd:ee:ff
# tplink adheres to ieee, Nax adheres to ietf # tplink adheres to ieee, Nax adheres to ietf
def ieee2ietf_mac_formater(inputmac): def ieee2ietf_mac_formater(inputmac):
return(inputmac.lower().replace('-',':')) return inputmac.lower().replace("-", ":")
def ietf2ieee_mac_formater(inputmac): def ietf2ieee_mac_formater(inputmac):
return(inputmac.upper().replace(':','-')) if not inputmac or not isinstance(inputmac, str):
mylog(
"minimal",
[
f"[{pluginName}] ietf2ieee_mac_formater ERROR: inputmac is not a string: {inputmac}"
],
)
return None
return inputmac.upper().replace(":", "-")
def get_mac_from_IP(target_IP): def get_mac_from_IP(target_IP):
from scapy.all import ARP, Ether, srp from scapy.all import ARP, Ether, srp
try: try:
arp_request = ARP(pdst=target_IP) arp_request = ARP(pdst=target_IP)
ether = Ether(dst="ff:ff:ff:ff:ff:ff") ether = Ether(dst="ff:ff:ff:ff:ff:ff")
packet = ether/arp_request packet = ether / arp_request
result = srp(packet, timeout=3, verbose=0)[0] result = srp(packet, timeout=3, verbose=0)[0]
if result: if result:
return result[0][1].hwsrc return result[0][1].hwsrc
else: else:
return None return None
except Exception as e: except Exception as e:
mylog('minimal', [f'[{pluginName}] get_mac_from_IP ERROR:{e}']) mylog("minimal", [f"[{pluginName}] get_mac_from_IP ERROR:{e}"])
return None return None
# #
# wrapper to call the omada python library's own wrapper # wrapper to call the omada python library's own wrapper
# it returns the output as a multiline python string # it returns the output as a multiline python string
# #
def callomada(myargs): def callomada(myargs):
arguments=" ".join(myargs) arguments = " ".join(myargs)
mylog('verbose', [f'[{pluginName}] callomada:{arguments}']) mylog("verbose", [f"[{pluginName}] callomada:{arguments}"])
from tplink_omada_client.cli import main as omada from tplink_omada_client.cli import main as omada
from contextlib import redirect_stdout from contextlib import redirect_stdout
omada_output = ''
omada_output = ""
retries = 2 retries = 2
while omada_output == '' and retries > 1: while omada_output == "" and retries > 1:
retries = retries - 1 retries = retries - 1
try: try:
mf = io.StringIO() mf = io.StringIO()
@@ -130,9 +146,13 @@ def callomada(myargs):
bar = omada(myargs) bar = omada(myargs)
omada_output = mf.getvalue() omada_output = mf.getvalue()
except Exception as e: except Exception as e:
mylog('minimal', [f'[{pluginName}] ERROR WHILE CALLING callomada:{arguments}\n {mf}']) mylog(
omada_output= '' "minimal",
return(omada_output) [f"[{pluginName}] ERROR WHILE CALLING callomada:{arguments}\n {mf}"],
)
omada_output = ""
return omada_output
# #
# extract all the mac addresses from a multilines text... # extract all the mac addresses from a multilines text...
@@ -143,34 +163,56 @@ def extract_mac_addresses(text):
mac_addresses = re.findall(mac_pattern, text) mac_addresses = re.findall(mac_pattern, text)
return ["".join(parts) for parts in mac_addresses] return ["".join(parts) for parts in mac_addresses]
def find_default_gateway_ip ():
#import netifaces def find_default_gateway_ip():
#gw = netifaces.gateways() # Get the routing table
#return(gw['default'][netifaces.AF_INET][0])
from scapy.all import conf, Route, sr1, IP, ICMP from scapy.all import conf, Route, sr1, IP, ICMP
default_route = conf.route.route("0.0.0.0")
return default_route[2] if default_route[2] else None routing_table = conf.route.routes
for route in routing_table:
# Each route is a tuple: (destination, netmask, gateway, iface, output_ip, metric)
destination, netmask, gateway, iface, output_ip, metric = route
# Look for the default route (destination and netmask are both 0.0.0.0)
if destination == 0 and netmask == 0 and gateway != "0.0.0.0":
mylog("verbose", [f"[DEBUG] Default Gateway IP: {gateway}"])
return gateway # Found the default gateway
return None # Default gateway not found
#return('192.168.0.1') def add_uplink(
uplink_mac,
switch_mac,
def add_uplink (uplink_mac, switch_mac, device_data_bymac, sadevices_linksbymac,port_byswitchmac_byclientmac): device_data_bymac,
#mylog(OMDLOGLEVEL, [f'[{pluginName}] trying to add uplink="{uplink_mac}" to switch="{switch_mac}"']) sadevices_linksbymac,
#mylog(OMDLOGLEVEL, [f'[{pluginName}] before adding:"{device_data_bymac[switch_mac]}"']) port_byswitchmac_byclientmac,
if device_data_bymac[switch_mac][SWITCH_AP] == 'null': ):
# mylog(OMDLOGLEVEL, [f'[{pluginName}] trying to add uplink="{uplink_mac}" to switch="{switch_mac}"'])
# mylog(OMDLOGLEVEL, [f'[{pluginName}] before adding:"{device_data_bymac[switch_mac]}"'])
if device_data_bymac[switch_mac][SWITCH_AP] == "null":
device_data_bymac[switch_mac][SWITCH_AP] = uplink_mac device_data_bymac[switch_mac][SWITCH_AP] = uplink_mac
if device_data_bymac[switch_mac][TYPE] == 'Switch' and device_data_bymac[uplink_mac][TYPE] == 'Switch': if (
device_data_bymac[switch_mac][TYPE] == "Switch"
and device_data_bymac[uplink_mac][TYPE] == "Switch"
):
port_to_uplink = port_byswitchmac_byclientmac[switch_mac][uplink_mac] port_to_uplink = port_byswitchmac_byclientmac[switch_mac][uplink_mac]
#find_port_of_uplink_switch(switch_mac, uplink_mac) # find_port_of_uplink_switch(switch_mac, uplink_mac)
else: else:
port_to_uplink=device_data_bymac[uplink_mac][PORT_SSID] port_to_uplink = device_data_bymac[uplink_mac][PORT_SSID]
device_data_bymac[switch_mac][PORT_SSID] = port_to_uplink device_data_bymac[switch_mac][PORT_SSID] = port_to_uplink
# mylog(OMDLOGLEVEL, [f'[{pluginName}] after adding:"{device_data_bymac[switch_mac]}"']) # mylog(OMDLOGLEVEL, [f'[{pluginName}] after adding:"{device_data_bymac[switch_mac]}"'])
for link in sadevices_linksbymac[switch_mac]: for link in sadevices_linksbymac[switch_mac]:
if device_data_bymac[link][SWITCH_AP] == 'null' and device_data_bymac[switch_mac][TYPE] == 'Switch': if (
add_uplink(switch_mac, link, device_data_bymac, sadevices_linksbymac,port_byswitchmac_byclientmac) device_data_bymac[link][SWITCH_AP] == "null"
and device_data_bymac[switch_mac][TYPE] == "Switch"
):
add_uplink(
switch_mac,
link,
device_data_bymac,
sadevices_linksbymac,
port_byswitchmac_byclientmac,
)
# ---------------------------------------------- # ----------------------------------------------
@@ -178,51 +220,69 @@ def add_uplink (uplink_mac, switch_mac, device_data_bymac, sadevices_linksbymac,
def main(): def main():
start_time = time.time() start_time = time.time()
mylog('verbose', [f'[{pluginName}] starting execution']) mylog("verbose", [f"[{pluginName}] starting execution"])
from database import DB from database import DB
from device import Device_obj from device import Device_obj
db = DB() # instance of class DB db = DB() # instance of class DB
db.open() db.open()
# Create a Device_obj instance # Create a Device_obj instance
device_handler = Device_obj(db) device_handler = Device_obj(db)
# Retrieve configuration settings # Retrieve configuration settings
# these should be self-explanatory # these should be self-explanatory
omada_sites = [] omada_sites = []
omada_username = get_setting_value('OMDSDN_username') omada_username = get_setting_value("OMDSDN_username")
omada_password = get_setting_value('OMDSDN_password') omada_password = get_setting_value("OMDSDN_password")
omada_sites = get_setting_value('OMDSDN_sites') omada_sites = get_setting_value("OMDSDN_sites")
omada_site = omada_sites[0] omada_site = omada_sites[0]
omada_url = get_setting_value('OMDSDN_url') omada_url = get_setting_value("OMDSDN_url")
omada_login = callomada(['-t','myomada','target','--url',omada_url,'--user',omada_username, omada_login = callomada(
'--password',omada_password,'--site',omada_site,'--set-default']) [
mylog('verbose', [f'[{pluginName}] login to omada result is: {omada_login}']) "-t",
"myomada",
"target",
"--url",
omada_url,
"--user",
omada_username,
"--password",
omada_password,
"--site",
omada_site,
"--set-default",
]
)
mylog("verbose", [f"[{pluginName}] login to omada result is: {omada_login}"])
clients_list = callomada(['-t','myomada','clients']) clients_list = callomada(["-t", "myomada", "clients"])
mylog('verbose', [f'[{pluginName}] clients found:"{clients_list.count("\n")}"\n{clients_list}']) mylog(
"verbose",
switches_and_aps = callomada(['-t','myomada','devices']) [f'[{pluginName}] clients found:"{clients_list.count("\n")}"\n{clients_list}'],
mylog('verbose', [f'[{pluginName}] omada devices (switches, access points) found:"{switches_and_aps.count("\n")}" \n {switches_and_aps}']) )
#some_setting = get_setting_value('OMDSDN_url')
#mylog(OMDLOGLEVEL, [f'[{pluginName}] some_setting value {some_setting}'])
mylog(OMDLOGLEVEL, [f'[{pluginName}] ffsb'])
switches_and_aps = callomada(["-t", "myomada", "devices"])
mylog(
"verbose",
[
f'[{pluginName}] omada devices (switches, access points) found:"{switches_and_aps.count("\n")}" \n {switches_and_aps}'
],
)
# some_setting = get_setting_value('OMDSDN_url')
# mylog(OMDLOGLEVEL, [f'[{pluginName}] some_setting value {some_setting}'])
mylog(OMDLOGLEVEL, [f"[{pluginName}] ffsb"])
# retrieve data # retrieve data
device_data = get_device_data(clients_list, switches_and_aps, device_handler) device_data = get_device_data(clients_list, switches_and_aps, device_handler)
# Process the data into native application tables # Process the data into native application tables
mylog('verbose', [f'[{pluginName}] New entries to create: "{len(device_data)}"']) mylog("verbose", [f'[{pluginName}] New entries to create: "{len(device_data)}"'])
if len(device_data) > 0: if len(device_data) > 0:
# insert devices into the lats_result.log # insert devices into the lats_result.log
# make sure the below mapping is mapped in config.json, for example: # make sure the below mapping is mapped in config.json, for example:
#"database_column_definitions": [ # "database_column_definitions": [
# { # {
# "column": "Object_PrimaryID", <--------- the value I save into primaryId # "column": "Object_PrimaryID", <--------- the value I save into primaryId
# "mapped_to_column": "cur_MAC", <--------- gets unserted into the CurrentScan DB table column cur_MAC # "mapped_to_column": "cur_MAC", <--------- gets unserted into the CurrentScan DB table column cur_MAC
@@ -230,91 +290,115 @@ def main():
# figure a way to run my udpate script delayed # figure a way to run my udpate script delayed
for device in device_data: for device in device_data:
mylog(OMDLOGLEVEL, [f'[{pluginName}] main parsing device: "{device}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] main parsing device: "{device}"'])
myport = device[PORT_SSID] if device[PORT_SSID].isdigit() else '' myport = device[PORT_SSID] if device[PORT_SSID].isdigit() else ""
myssid = device[PORT_SSID] if not device[PORT_SSID].isdigit() else '' myssid = device[PORT_SSID] if not device[PORT_SSID].isdigit() else ""
ParentNetworkNode = ieee2ietf_mac_formater(device[SWITCH_AP]) if device[SWITCH_AP] != 'Internet' else 'Internet' ParentNetworkNode = (
mymac = ieee2ietf_mac_formater(device[MAC]) ieee2ietf_mac_formater(device[SWITCH_AP])
plugin_objects.add_object( if device[SWITCH_AP] != "Internet"
primaryId = mymac, # MAC else "Internet"
secondaryId = device[IP], # IP )
watched1 = device[NAME], # NAME/HOSTNAME mymac = ieee2ietf_mac_formater(device[MAC])
watched2 = ParentNetworkNode, # PARENT NETWORK NODE MAC plugin_objects.add_object(
watched3 = myport, # PORT primaryId=mymac, # MAC
watched4 = myssid, # SSID secondaryId=device[IP], # IP
extra = device[TYPE], watched1=device[NAME], # NAME/HOSTNAME
#omada_site, # SITENAME (cur_NetworkSite) or VENDOR (cur_Vendor) (PICK one and adjust config.json -> "column": "Extra") watched2=ParentNetworkNode, # PARENT NETWORK NODE MAC
foreignKey = device[MAC].lower().replace('-',':')) # usually MAC watched3=myport, # PORT
watched4=myssid, # SSID
extra=device[TYPE],
# omada_site, # SITENAME (cur_NetworkSite) or VENDOR (cur_Vendor) (PICK one and adjust config.json -> "column": "Extra")
foreignKey=device[MAC].lower().replace("-", ":"),
) # usually MAC
mylog('verbose', [f'[{pluginName}] New entries: "{mymac:<18}, {device[IP]:<16}, {device[NAME]:<63}, {ParentNetworkNode:<18}, {myport:<4}, {myssid:<32}, {device[TYPE]}"']) mylog(
mylog('verbose', [f'[{pluginName}] New entries: "{len(device_data)}"']) "verbose",
[
f'[{pluginName}] New entries: "{mymac:<18}, {device[IP]:<16}, {device[NAME]:<63}, {ParentNetworkNode:<18}, {myport:<4}, {myssid:<32}, {device[TYPE]}"'
],
)
mylog("verbose", [f'[{pluginName}] New entries: "{len(device_data)}"'])
# log result # log result
plugin_objects.write_result_file() plugin_objects.write_result_file()
#mylog(OMDLOGLEVEL, [f'[{pluginName}] TEST name from MAC: {device_handler.getValueWithMac('devName','00:e2:59:00:a0:8e')}']) # mylog(OMDLOGLEVEL, [f'[{pluginName}] TEST name from MAC: {device_handler.getValueWithMac('devName','00:e2:59:00:a0:8e')}'])
#mylog(OMDLOGLEVEL, [f'[{pluginName}] TEST MAC from IP: {get_mac_from_IP('192.168.0.1')} also {ietf2ieee_mac_formater(get_mac_from_IP('192.168.0.1'))}']) # mylog(OMDLOGLEVEL, [f'[{pluginName}] TEST MAC from IP: {get_mac_from_IP('192.168.0.1')} also {ietf2ieee_mac_formater(get_mac_from_IP('192.168.0.1'))}'])
end_time = time.time() end_time = time.time()
mylog('verbose', [f'[{pluginName}] execution completed in {end_time - start_time:.2f} seconds']) mylog(
"verbose",
[f"[{pluginName}] execution completed in {end_time - start_time:.2f} seconds"],
)
return 0 return 0
def get_omada_devices_details(msadevice_data): def get_omada_devices_details(msadevice_data):
mthisswitch = msadevice_data[dMAC] mthisswitch = msadevice_data[dMAC]
mtype = msadevice_data[dTYPE] mtype = msadevice_data[dTYPE]
mswitch_detail = '' mswitch_detail = ""
mswitch_dump = '' mswitch_dump = ""
if mtype == 'ap': if mtype == "ap":
mswitch_detail = callomada(['access-point', mthisswitch]) mswitch_detail = callomada(["access-point", mthisswitch])
elif mtype == 'switch': elif mtype == "switch":
mswitch_detail = callomada(['switch', mthisswitch]) mswitch_detail = callomada(["switch", mthisswitch])
mswitch_dump = callomada(['-t','myomada','switch','-d',mthisswitch]) mswitch_dump = callomada(["-t", "myomada", "switch", "-d", mthisswitch])
else: else:
mswitch_detail = '' mswitch_detail = ""
nswitch_dump = '' nswitch_dump = ""
return mswitch_detail, mswitch_dump return mswitch_detail, mswitch_dump
def get_omada_devices_details_parallel(msadevice_data): def get_omada_devices_details_parallel(msadevice_data):
mthisswitch = msadevice_data[dMAC] mthisswitch = msadevice_data[dMAC]
mtype = msadevice_data[dTYPE] mtype = msadevice_data[dTYPE]
mswitch_detail = '' mswitch_detail = ""
mswitch_dump = '' mswitch_dump = ""
if mtype == 'ap': if mtype == "ap":
mswitch_detail = subprocess.run('omada access-point '+mthisswitch, capture_output=True, text=True, shell=True).stdout mswitch_detail = subprocess.run(
elif mtype == 'switch': "omada access-point " + mthisswitch,
mswitch_detail = subprocess.run('omada switch '+mthisswitch, capture_output=True, text=True, shell=True).stdout capture_output=True,
mswitch_dump = subprocess.run('omada access-point '+mthisswitch, capture_output=True, text=True, shell=True).stdout text=True,
shell=True,
).stdout
elif mtype == "switch":
mswitch_detail = subprocess.run(
"omada switch " + mthisswitch, capture_output=True, text=True, shell=True
).stdout
mswitch_dump = subprocess.run(
"omada access-point " + mthisswitch,
capture_output=True,
text=True,
shell=True,
).stdout
else: else:
mswitch_detail = '' mswitch_detail = ""
mswitch_dump = '' mswitch_dump = ""
return mthisswitch, mswitch_detail, mswitch_dump return mthisswitch, mswitch_detail, mswitch_dump
# ---------------------------------------------- # ----------------------------------------------
# retrieve data # retrieve data
def get_device_data(omada_clients_output,switches_and_aps,device_handler): def get_device_data(omada_clients_output, switches_and_aps, device_handler):
# sample omada devices input format: # sample omada devices input format:
# 0.MAC 1.IP 2.type 3.status 4.name 5.model # 0.MAC 1.IP 2.type 3.status 4.name 5.model
#40-AE-30-A5-A7-50 192.168.0.11 ap CONNECTED office_Access_point EAP773(US) v1.0 # 40-AE-30-A5-A7-50 192.168.0.11 ap CONNECTED office_Access_point EAP773(US) v1.0
#B0-95-75-46-0C-39 192.168.0.4 switch CONNECTED pantry12 T1600G-52PS v4.0 # B0-95-75-46-0C-39 192.168.0.4 switch CONNECTED pantry12 T1600G-52PS v4.0
# #
# sample target output: # sample target output:
# 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, 5 TYPE # 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, 5 TYPE
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', '17', '40-AE-30-A5-A7-50, 'Switch']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', '17', '40-AE-30-A5-A7-50, 'Switch']"
#constants # constants
sadevices_macbyname = {} sadevices_macbyname = {}
sadevices_macbymac = {} sadevices_macbymac = {}
sadevices_linksbymac = {} sadevices_linksbymac = {}
port_byswitchmac_byclientmac = {} port_byswitchmac_byclientmac = {}
device_data_bymac = {} device_data_bymac = {}
device_data_mac_byip = {} device_data_mac_byip = {}
omada_force_overwrite = get_setting_value('OMDSDN_force_overwrite') omada_force_overwrite = get_setting_value("OMDSDN_force_overwrite")
switch_details = {} switch_details = {}
switch_dumps = {} switch_dumps = {}
''' """
command = 'which omada' command = 'which omada'
def run_command(command, index): def run_command(command, index):
result = subprocess.run(command, capture_output=True, text=True, shell=True) result = subprocess.run(command, capture_output=True, text=True, shell=True)
@@ -322,108 +406,125 @@ def get_device_data(omada_clients_output,switches_and_aps,device_handler):
myindex, command_output= run_command(command, 2) myindex, command_output= run_command(command, 2)
mylog('verbose', [f'[{pluginName}] command={command} index={myindex} results={command_output}']) mylog('verbose', [f'[{pluginName}] command={command} index={myindex} results={command_output}'])
''' """
sadevices = switches_and_aps.splitlines() sadevices = switches_and_aps.splitlines()
mylog(OMDLOGLEVEL, [f'[{pluginName}] switches_and_aps rows: "{len(sadevices)}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] switches_and_aps rows: "{len(sadevices)}"'])
with multiprocessing.Pool(processes = PARALLELISM) as mypool: with multiprocessing.Pool(processes=PARALLELISM) as mypool:
oresults = mypool.map(get_omada_devices_details_parallel, [sadevice.split() for sadevice in sadevices]) oresults = mypool.map(
get_omada_devices_details_parallel,
[sadevice.split() for sadevice in sadevices],
)
for thisswitch, details, dump in oresults: for thisswitch, details, dump in oresults:
switch_details[thisswitch] = details switch_details[thisswitch] = details
switch_dumps[thisswitch] = dump switch_dumps[thisswitch] = dump
mylog(OMDLOGLEVEL, [f'[{pluginName}] switch={thisswitch} details={details}']) mylog(OMDLOGLEVEL, [f"[{pluginName}] switch={thisswitch} details={details}"])
''' """
for sadevice in sadevices: for sadevice in sadevices:
sadevice_data = sadevice.split() sadevice_data = sadevice.split()
thisswitch = sadevice_data[dMAC] thisswitch = sadevice_data[dMAC]
thistype = sadevice_data[dTYPE] thistype = sadevice_data[dTYPE]
switch_details[thisswitch], switch_dumps[thisswitch] = get_omada_devices_details(sadevice_data) switch_details[thisswitch], switch_dumps[thisswitch] = get_omada_devices_details(sadevice_data)
''' """
mylog('verbose', [f'[{pluginName}] switches details collected "{len(switch_details)}"']) mylog(
mylog('verbose', [f'[{pluginName}] dump details collected "{len(switch_details)}"']) "verbose",
[f'[{pluginName}] switches details collected "{len(switch_details)}"'],
)
mylog("verbose", [f'[{pluginName}] dump details collected "{len(switch_details)}"'])
for sadevice in sadevices: for sadevice in sadevices:
sadevice_data = sadevice.split() sadevice_data = sadevice.split()
thisswitch = sadevice_data[dMAC] thisswitch = sadevice_data[dMAC]
sadevices_macbyname[sadevice_data[4]] = thisswitch sadevices_macbyname[sadevice_data[4]] = thisswitch
if sadevice_data[dTYPE] == 'ap': if sadevice_data[dTYPE] == "ap":
sadevice_type = 'AP' sadevice_type = "AP"
#sadevice_details = callomada(['access-point', thisswitch]) # sadevice_details = callomada(['access-point', thisswitch])
sadevice_details = switch_details[thisswitch] sadevice_details = switch_details[thisswitch]
if sadevice_details == '': if sadevice_details == "":
sadevice_links = [thisswitch] sadevice_links = [thisswitch]
else: else:
sadevice_links = extract_mac_addresses(sadevice_details) sadevice_links = extract_mac_addresses(sadevice_details)
sadevices_linksbymac[thisswitch] = sadevice_links[1:] sadevices_linksbymac[thisswitch] = sadevice_links[1:]
#mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch details: "{sadevice_details}"']) # mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch details: "{sadevice_details}"'])
#mylog(OMDLOGLEVEL, [f'[{pluginName}]links are: "{sadevice_links}"']) # mylog(OMDLOGLEVEL, [f'[{pluginName}]links are: "{sadevice_links}"'])
#mylog(OMDLOGLEVEL, [f'[{pluginName}]linksbymac are: "{sadevices_linksbymac[thisswitch]}"']) # mylog(OMDLOGLEVEL, [f'[{pluginName}]linksbymac are: "{sadevices_linksbymac[thisswitch]}"'])
elif sadevice_data[dTYPE] == 'switch': elif sadevice_data[dTYPE] == "switch":
sadevice_type = 'Switch' sadevice_type = "Switch"
#sadevice_details=callomada(['switch', thisswitch]) # sadevice_details=callomada(['switch', thisswitch])
sadevice_details = switch_details[thisswitch] sadevice_details = switch_details[thisswitch]
if sadevice_details == '': if sadevice_details == "":
sadevice_links = [thisswitch] sadevice_links = [thisswitch]
else: else:
sadevice_links=extract_mac_addresses(sadevice_details) sadevice_links = extract_mac_addresses(sadevice_details)
sadevices_linksbymac[thisswitch] = sadevice_links[1:] sadevices_linksbymac[thisswitch] = sadevice_links[1:]
# recovering the list of switches connected to sadevice switch and on which port... # recovering the list of switches connected to sadevice switch and on which port...
#switchdump = callomada(['-t','myomada','switch','-d',thisswitch]) # switchdump = callomada(['-t','myomada','switch','-d',thisswitch])
switchdump = switch_dumps[thisswitch] switchdump = switch_dumps[thisswitch]
mylog(OMDLOGLEVEL, [f'[{pluginName}] switchdump: {switchdump}']) mylog(OMDLOGLEVEL, [f"[{pluginName}] switchdump: {switchdump}"])
port_byswitchmac_byclientmac[thisswitch] = {} port_byswitchmac_byclientmac[thisswitch] = {}
for link in sadevices_linksbymac[thisswitch]: for link in sadevices_linksbymac[thisswitch]:
port_pattern = r"(?:{[^}]*\"port\"\: )([0-9]+)(?=[^}]*"+re.escape(link)+r")" port_pattern = (
myport = re.findall(port_pattern, switchdump,re.DOTALL) r"(?:{[^}]*\"port\"\: )([0-9]+)(?=[^}]*" + re.escape(link) + r")"
#mylog(OMDLOGLEVEL, [f'[{pluginName}] switchdump: link={link} myport:{myport}']) )
port_byswitchmac_byclientmac[thisswitch][link] = myport[0] if myport else '' myport = re.findall(port_pattern, switchdump, re.DOTALL)
#mylog(OMDLOGLEVEL, [f'[{pluginName}]links are: "{sadevice_links}"']) # mylog(OMDLOGLEVEL, [f'[{pluginName}] switchdump: link={link} myport:{myport}'])
#mylog(OMDLOGLEVEL, [f'[{pluginName}]linksbymac are: "{sadevices_linksbymac[thisswitch]}"']) port_byswitchmac_byclientmac[thisswitch][link] = (
#mylog(OMDLOGLEVEL, [f'[{pluginName}]ports of each links are: "{port_byswitchmac_byclientmac[thisswitch]}"']) myport[0] if myport else ""
#mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch details: "{sadevice_details}"']) )
# mylog(OMDLOGLEVEL, [f'[{pluginName}]links are: "{sadevice_links}"'])
# mylog(OMDLOGLEVEL, [f'[{pluginName}]linksbymac are: "{sadevices_linksbymac[thisswitch]}"'])
# mylog(OMDLOGLEVEL, [f'[{pluginName}]ports of each links are: "{port_byswitchmac_byclientmac[thisswitch]}"'])
# mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch details: "{sadevice_details}"'])
else: else:
sadevice_type = 'null' sadevice_type = "null"
sadevice_details='null' sadevice_details = "null"
device_data_bymac[thisswitch] = [thisswitch, sadevice_data[dIP], sadevice_data[dNAME], 'null', 'null',sadevice_type] device_data_bymac[thisswitch] = [
thisswitch,
sadevice_data[dIP],
sadevice_data[dNAME],
"null",
"null",
sadevice_type,
]
device_data_mac_byip[sadevice_data[dIP]] = thisswitch device_data_mac_byip[sadevice_data[dIP]] = thisswitch
foo=[thisswitch, sadevice_data[1], sadevice_data[4], 'null', 'null'] foo = [thisswitch, sadevice_data[1], sadevice_data[4], "null", "null"]
mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch: "{foo}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}]adding switch: "{foo}"'])
# sadevices_macbymac[thisswitch] = thisswitch # sadevices_macbymac[thisswitch] = thisswitch
mylog(OMDLOGLEVEL, [f'[{pluginName}] switch_macbyname: "{sadevices_macbyname}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] switch_macbyname: "{sadevices_macbyname}"'])
mylog(OMDLOGLEVEL, [f'[{pluginName}] switches: "{device_data_bymac}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] switches: "{device_data_bymac}"'])
# do some processing, call exteranl APIs, and return a device list # do some processing, call exteranl APIs, and return a device list
# ... # ...
# sample omada clients input format: # sample omada clients input format:
# 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID, # 0 MAC, 1 IP, 2 Name, 3 switch/AP, 4 port/SSID,
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', 'myssid_name2', '(office_Access_point)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', '1A-2B-3C-4D-5E-6F', 'myssid_name2', '(office_Access_point)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-01', '192.168.0.153', 'frontyard_ESP_29E753', 'pantry12', '(48)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-01', '192.168.0.153', 'frontyard_ESP_29E753', 'pantry12', '(48)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-02', '192.168.0.1', 'bastion', 'office24', '(23)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-02', '192.168.0.1', 'bastion', 'office24', '(23)']"
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-03', '192.168.0.226', 'brick', 'myssid_name3', '(office_Access_point)']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-03', '192.168.0.226', 'brick', 'myssid_name3', '(office_Access_point)']"
# sample target output: # sample target output:
# 0 MAC, 1 IP, 2 Name, 3 MAC of switch/AP, 4 port/SSID, 5 TYPE # 0 MAC, 1 IP, 2 Name, 3 MAC of switch/AP, 4 port/SSID, 5 TYPE
#17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', 'brick', 'office_Access_point','myssid_name2', , 'Switch']" # 17:27:10 [<unique_prefix>] token: "['1A-2B-3C-4D-5E-6F', '192.168.0.217', 'brick', 'office_Access_point','myssid_name2', , 'Switch']"
odevices = omada_clients_output.splitlines() odevices = omada_clients_output.splitlines()
mylog(OMDLOGLEVEL, [f'[{pluginName}] omada_clients_outputs rows: "{len(odevices)}"']) mylog(
OMDLOGLEVEL, [f'[{pluginName}] omada_clients_outputs rows: "{len(odevices)}"']
)
omada_clients_to_rename = [] omada_clients_to_rename = []
for odevice in odevices: for odevice in odevices:
odevice_data = odevice.split() odevice_data = odevice.split()
odevice_data_reordered = [ MAC, IP, NAME, SWITCH_AP, PORT_SSID, TYPE] odevice_data_reordered = [MAC, IP, NAME, SWITCH_AP, PORT_SSID, TYPE]
odevice_data_reordered[MAC]=odevice_data[cMAC] odevice_data_reordered[MAC] = odevice_data[cMAC]
odevice_data_reordered[IP]=odevice_data[cIP] odevice_data_reordered[IP] = odevice_data[cIP]
real_naxname = device_handler.getValueWithMac('devName',ieee2ietf_mac_formater(odevice_data[cMAC])) real_naxname = device_handler.getValueWithMac(
"devName", ieee2ietf_mac_formater(odevice_data[cMAC])
)
# #
# if the name stored in Nax for a device is empty or the MAC addres or has some parenthhesis or is the same as in omada # if the name stored in Nax for a device is empty or the MAC addres or has some parenthhesis or is the same as in omada
@@ -432,38 +533,59 @@ def get_device_data(omada_clients_output,switches_and_aps,device_handler):
naxname = real_naxname naxname = real_naxname
if real_naxname != None: if real_naxname != None:
if '(' in real_naxname: if "(" in real_naxname:
# removing parenthesis and domains from the name # removing parenthesis and domains from the name
naxname = real_naxname.split('(')[0] naxname = real_naxname.split("(")[0]
if naxname != None and '.' in naxname: if naxname != None and "." in naxname:
naxname = naxname.split('.')[0] naxname = naxname.split(".")[0]
if naxname in ( None, 'null', '' ): if naxname in (None, "null", ""):
naxname = odevice_data[cNAME] if odevice_data[cNAME] != '' else odevice_data[cMAC] naxname = (
odevice_data[cNAME] if odevice_data[cNAME] != "" else odevice_data[cMAC]
)
naxname = naxname.strip() naxname = naxname.strip()
mylog('debug', [f'[{pluginName}] TEST name from MAC: {naxname}']) mylog("debug", [f"[{pluginName}] TEST name from MAC: {naxname}"])
if odevice_data[cNAME] in ('null', ''): if odevice_data[cNAME] in ("null", ""):
mylog('verbose', [f'[{pluginName}] updating omada server because odevice_data is: {odevice_data[cNAME]} and naxname is: "{naxname}"']) mylog(
omada_clients_to_rename.append(['set-client-name',odevice_data[cMAC], naxname]) "verbose",
#callomada(['set-client-name', odevice_data[cMAC], naxname]) [
f'[{pluginName}] updating omada server because odevice_data is: {odevice_data[cNAME]} and naxname is: "{naxname}"'
],
)
omada_clients_to_rename.append(
["set-client-name", odevice_data[cMAC], naxname]
)
# callomada(['set-client-name', odevice_data[cMAC], naxname])
odevice_data_reordered[NAME] = naxname odevice_data_reordered[NAME] = naxname
elif odevice_data[cNAME] == odevice_data[cMAC] and ieee2ietf_mac_formater(naxname) != ieee2ietf_mac_formater(odevice_data[cNAME]) : elif odevice_data[cNAME] == odevice_data[cMAC] and ieee2ietf_mac_formater(
mylog('verbose', [f'[{pluginName}] updating omada server because odevice_data is: "{odevice_data[cNAME]} and naxname is: "{naxname}"']) naxname
omada_clients_to_rename.append(['set-client-name',odevice_data[cMAC], naxname]) ) != ieee2ietf_mac_formater(odevice_data[cNAME]):
#callomada(['set-client-name', odevice_data[cMAC], naxname]) mylog(
"verbose",
[
f'[{pluginName}] updating omada server because odevice_data is: "{odevice_data[cNAME]} and naxname is: "{naxname}"'
],
)
omada_clients_to_rename.append(
["set-client-name", odevice_data[cMAC], naxname]
)
# callomada(['set-client-name', odevice_data[cMAC], naxname])
odevice_data_reordered[NAME] = naxname odevice_data_reordered[NAME] = naxname
else: else:
if omada_force_overwrite and naxname != odevice_data[cNAME] : if omada_force_overwrite and naxname != odevice_data[cNAME]:
mylog('verbose', [f'[{pluginName}] updating omada server because odevice_data is: "{odevice_data[cNAME]} and naxname is: "{naxname}"']) mylog(
omada_clients_to_rename.append(['set-client-name',odevice_data[cMAC], naxname]) "verbose",
#callomada(['set-client-name', odevice_data[cMAC], naxname]) [
f'[{pluginName}] updating omada server because odevice_data is: "{odevice_data[cNAME]} and naxname is: "{naxname}"'
],
)
omada_clients_to_rename.append(
["set-client-name", odevice_data[cMAC], naxname]
)
# callomada(['set-client-name', odevice_data[cMAC], naxname])
odevice_data_reordered[NAME] = naxname odevice_data_reordered[NAME] = naxname
mightbeport = odevice_data[cPORT_SSID].lstrip("(")
mightbeport = mightbeport.rstrip(")")
mightbeport = odevice_data[cPORT_SSID].lstrip('(')
mightbeport = mightbeport.rstrip(')')
if mightbeport.isdigit(): if mightbeport.isdigit():
odevice_data_reordered[SWITCH_AP] = odevice_data[cSWITCH_AP] odevice_data_reordered[SWITCH_AP] = odevice_data[cSWITCH_AP]
odevice_data_reordered[PORT_SSID] = mightbeport odevice_data_reordered[PORT_SSID] = mightbeport
@@ -476,42 +598,57 @@ def get_device_data(omada_clients_output,switches_and_aps,device_handler):
mightbemac = sadevices_macbyname[odevice_data_reordered[SWITCH_AP]] mightbemac = sadevices_macbyname[odevice_data_reordered[SWITCH_AP]]
odevice_data_reordered[SWITCH_AP] = mightbemac odevice_data_reordered[SWITCH_AP] = mightbemac
except KeyError: except KeyError:
mylog(OMDLOGLEVEL, [f'[{pluginName}] could not find the mac adddress for: "{odevice_data_reordered[SWITCH_AP]}"']) mylog(
OMDLOGLEVEL,
[
f'[{pluginName}] could not find the mac adddress for: "{odevice_data_reordered[SWITCH_AP]}"'
],
)
# adding the type # adding the type
odevice_data_reordered[TYPE] = 'null' odevice_data_reordered[TYPE] = "null"
device_data_bymac[odevice_data_reordered[MAC]] = odevice_data_reordered device_data_bymac[odevice_data_reordered[MAC]] = odevice_data_reordered
device_data_mac_byip[odevice_data_reordered[IP]] = odevice_data_reordered[MAC] device_data_mac_byip[odevice_data_reordered[IP]] = odevice_data_reordered[MAC]
mylog(OMDLOGLEVEL, [f'[{pluginName}] tokens: "{odevice_data}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] tokens: "{odevice_data}"'])
mylog(OMDLOGLEVEL, [f'[{pluginName}] tokens_reordered: "{odevice_data_reordered}"']) mylog(
OMDLOGLEVEL,
[f'[{pluginName}] tokens_reordered: "{odevice_data_reordered}"'],
)
# RENAMING # RENAMING
#for omada_client_to_rename in omada_clients_to_rename: # for omada_client_to_rename in omada_clients_to_rename:
# mylog('verbose', [f'[{pluginName}] calling omada: "{omada_client_to_rename}"']) # mylog('verbose', [f'[{pluginName}] calling omada: "{omada_client_to_rename}"'])
#callomada(omada_client_to_rename) # callomada(omada_client_to_rename)
# populating the uplinks nodes of the omada switches and access points manually # populating the uplinks nodes of the omada switches and access points manually
# since OMADA SDN makes is unreliable if the gateway is not their own tplink hardware... # since OMADA SDN makes is unreliable if the gateway is not their own tplink hardware...
# #
with multiprocessing.Pool(processes = PARALLELISM) as mypool2: with multiprocessing.Pool(processes=PARALLELISM) as mypool2:
oresults = mypool2.map(callomada, omada_clients_to_rename) oresults = mypool2.map(callomada, omada_clients_to_rename)
mylog(OMDLOGLEVEL, [f'[{pluginName}] results are: "{oresults}"']) mylog(OMDLOGLEVEL, [f'[{pluginName}] results are: "{oresults}"'])
# step1 let's find the the default router # step1 let's find the the default router
# #
default_router_ip = find_default_gateway_ip() default_router_ip = find_default_gateway_ip()
default_router_mac = ietf2ieee_mac_formater(get_mac_from_IP(default_router_ip)) default_router_mac = ietf2ieee_mac_formater(get_mac_from_IP(default_router_ip))
device_data_bymac[default_router_mac][TYPE] = 'Firewall' device_data_bymac[default_router_mac][TYPE] = "Firewall"
# step2 let's find the first switch and set the default router parent to internet # step2 let's find the first switch and set the default router parent to internet
first_switch=device_data_bymac[default_router_mac][SWITCH_AP] first_switch = device_data_bymac[default_router_mac][SWITCH_AP]
device_data_bymac[default_router_mac][SWITCH_AP] = 'Internet' device_data_bymac[default_router_mac][SWITCH_AP] = "Internet"
# step3 let's set the switch connected to the default gateway uplink to the default gateway and hardcode port to 1 for now: # step3 let's set the switch connected to the default gateway uplink to the default gateway and hardcode port to 1 for now:
#device_data_bymac[first_switch][SWITCH_AP]=default_router_mac # device_data_bymac[first_switch][SWITCH_AP]=default_router_mac
#device_data_bymac[first_switch][SWITCH_AP][PORT_SSID] = '1' # device_data_bymac[first_switch][SWITCH_AP][PORT_SSID] = '1'
# step4, let's go recursively through switches other links to mark update their uplinks # step4, let's go recursively through switches other links to mark update their uplinks
# and pray it ends one day... # and pray it ends one day...
# #
if len(sadevices) > 0: if len(sadevices) > 0:
add_uplink(default_router_mac,first_switch, device_data_bymac,sadevices_linksbymac,port_byswitchmac_byclientmac) add_uplink(
default_router_mac,
first_switch,
device_data_bymac,
sadevices_linksbymac,
port_byswitchmac_byclientmac,
)
return device_data_bymac.values() return device_data_bymac.values()
if __name__ == '__main__':
if __name__ == "__main__":
main() main()