From dda0363f8f26a24d56b470c8446af86d6435489d Mon Sep 17 00:00:00 2001 From: Nico Darrow Date: Mon, 28 Sep 2020 18:31:18 -0400 Subject: [PATCH] BUUUUNCH of fixes in this one Fixed -ability to reprovision a port, or if it's similiar, clear the tag to remove from scope -issue withduplicate AMC addresses on the source config files, fixed that with some duct tape -added device status check before checking switch, so offline or unprovisioned switches don't consume cycles -added ability to handle more than 1000 clients for monitoring -allowed "alerting" devices to be in-scope, had some bad DNS entries, prevented from being provisioned --- autoMAC.py | 69 ++++++++++++++++++++++++++++++++++++++++++++--------- switchDB.py | 12 +++++++++- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/autoMAC.py b/autoMAC.py index 0fea9e6..ffd91b5 100755 --- a/autoMAC.py +++ b/autoMAC.py @@ -36,6 +36,8 @@ ### USER CONFIGURABLE SETTINGS +org_id = '5723437235866696' #this is the org you want to monitor/configure + allowHistoryConfigs = True #this allows it to use historic configs/mac-addresstables allowProfileConfigs = True #this allows it to "guess" on the profile based on MAC/OUI/CDP/LLDP/Vendor WRITE = True #set this to False to test and populate debug log files @@ -128,7 +130,6 @@ def validSN(SN, devices): # the function goes through each switch and assigns priming VLAN and preps it for provisioning def switch_wipe(): dashboard = meraki.DashboardAPI(api_key=None, base_url='https://api.meraki.com/api/v1/', print_console=False) - org_id = '577586652210266696' networks = dashboard.organizations.getOrganizationNetworks(org_id) networks_inscope = [] # target networks @@ -136,11 +137,13 @@ def switch_wipe(): if n['tags'] is not None and 'autoMAC' in n['tags']: networks_inscope.append(n) + switches_inscope = [] devices_inscope = [] for n in networks_inscope: #devices = dashboarad.devices.getNetworkDevices(n['id']) devices = dashboard.networks.getNetworkDevices(n['id']) + for d in devices: if 'tags' in d and tag_switch_TARGET in d['tags']: devices_inscope.append(d) @@ -208,7 +211,7 @@ def main(): #client_load(clientDB) #this loads meraki "snapshot", doesn't include voice vlans, need to fix that msDB = [] - sDir = "cisco/" + sDir = "cisco/paris_raw2/" if allowHistoryConfigs: cisco_load(msDB, clientDB, sDir) @@ -224,7 +227,6 @@ def main(): # Fire up Meraki API and build DB's dashboard = meraki.DashboardAPI(api_key=None, base_url='https://api.meraki.com/api/v1/', log_file_prefix=__file__[:-3], print_console=False) loop = True - org_id = '577586652210266696' #load Port Config detault library PC = portConfig() @@ -243,6 +245,13 @@ def main(): for n in networks: if n['tags'] is not None and 'autoMAC' in n['tags']: networks_inscope.append(n) + + online_devices = [] + stats = dashboard.organizations.getOrganizationDevicesStatuses(org_id) + for s in stats: + if s['status'] == 'online' or s['status'] == 'alerting': + online_devices.append(s['serial']) + switches_inscope = [] devices_inscope = [] @@ -254,8 +263,9 @@ def main(): for d in devices: if 'tags' in d and tag_switch_TARGET in d['tags']: #dashboard.devices.blinkNetworkDeviceLeds(n['id'], serial=d['serial'], duration=5, duty=10, period=100 ) - dashboard.devices.blinkDeviceLeds(serial=d['serial'], duration=5, duty=10, period=100 ) - devices_inscope.append(d) + if d['serial'] in online_devices: + dashboard.devices.blinkDeviceLeds(serial=d['serial'], duration=5, duty=10, period=100 ) + devices_inscope.append(d) print(f'{bcolors.OKBLUE}Networks Inscope:') for n in networks_inscope: @@ -309,14 +319,36 @@ def main(): # print() port_changes = [] - + total_clients = 0 # new network device function, works at network level instead of querying each switch for n in networks_inscope: netid = n['id'] #clients = dashboard.clients.getNetworkClients(netid, perPage=1000) clients = dashboard.networks.getNetworkClients(netid, perPage=1000) - + lastId = "" + if len(clients) == 1000: + lastId = clients[999]['id'] + clients = clients + dashboard.networks.getNetworkClients(netid, perPage=1000, startingAfter=lastId) + lastId = clients[len(clients)-1]['id'] + newclients = dashboard.networks.getNetworkClients(netid, perPage=1000, startingAfter=lastId) + while len(newclients) >= 1: + #print(f'Clients {len(clients)}') + #print(f'NewClients {len(newclients)}') + #print(lastId) + clients = clients + newclients + lastId = newclients[len(newclients)-1]['id'] + newclients = dashboard.networks.getNetworkClients(netid, perPage=1000, startingAfter=lastId) + if len(newclients) <= 1: + break + + + print(f'{bcolors.OKBLUE}Detected total {bcolors.WARNING}{len(clients)}{bcolors.OKBLUE} in Network[{bcolors.WARNING}{n["name"]}{bcolors.OKBLUE}]') + total_clients = total_clients + len(clients) + print(f'{bcolors.OKBLUE}TOTAL Clients Detected: {bcolors.WARNING}{len(clients)}{bcolors.OKBLUE} in {bcolors.WARNING}ALL{bcolors.OKBLUE} networks') + for c in clients: #interate through the ACTIVE clients on dashboard (target switches) + if c['status'] == "Offline": + continue update = False serial = "" serial = c['recentDeviceSerial'] @@ -332,11 +364,13 @@ def main(): vlan = int(sourceClient['vlan']) update = True ovlan = int(c['vlan']) - print(f'{bcolors.FAIL}VLAN Misconfiguration Client activeVlan[{bcolors.WARNING}{ovlan}{bcolors.FAIL}] OriginalVlan[{bcolors.WARNING}{vlan}{bcolors.FAIL}]') - #print(c) + #print(f'{bcolors.OKGREEN}{c}{bcolors.ENDC}') if isActivePort(serial, port, ports_inscope): + + print(f'{bcolors.FAIL}VLAN Misconfiguration Client activeVlan[{bcolors.WARNING}{ovlan}{bcolors.FAIL}] OriginalVlan[{bcolors.WARNING}{vlan}{bcolors.FAIL}] Mac[{bcolors.WARNING}{c["mac"]}{bcolors.FAIL}] Manufacturer[{bcolors.WARNING}{c["manufacturer"]}{bcolors.FAIL}] Desc[{bcolors.WARNING}{c["description"]}{bcolors.FAIL}]') + # if there's a change, make an update if update and c['status'] == "Online": #Changes is to be made and port is up #print(c) @@ -421,7 +455,12 @@ def main(): orig_mac = findMAC(msDB,mac) orig_sw = getSW(msDB,orig_mac['name']) orig_port = orig_sw.parsedCFG(orig_mac['port']) - oVlan = orig_port['vlan'] + oVlan = vlan + try: + oVlan = orig_port['vlan'] + except: + print(f'Failure on port: {orig_port} NewPort[{newPort}]') + if 'voiceVlan' in orig_port: ovoiceVlan = orig_port['voiceVlan'] else: @@ -454,7 +493,15 @@ def main(): else: - print(f'{bcolors.FAIL}Port is already configured{bcolors.WARNING}!!!!!{bcolors.OKBLUE}') + print(f'{bcolors.FAIL}Port is already configured{bcolors.WARNING}!!!!! Clearing port tag{bcolors.OKBLUE}') + if WRITE: + res = dashboard.switch.updateDeviceSwitchPort(S1, P1, tags=tags) + log(f'[WRITE] API updateDeviceSwitchPorts') + else: + print(f'{bcolors.OKGREEN}[READ-ONLY BYPASS]') + log(f'[READ-ONLY] API updateDeviceSwitchPorts') + + print() print() diff --git a/switchDB.py b/switchDB.py index eb775a5..400e313 100755 --- a/switchDB.py +++ b/switchDB.py @@ -38,6 +38,12 @@ def parseMAC(self): # print(f'{vlan} {mac} {port}') + #print(f'ISTRUNK[{port}]') + #print(self.isTrunk(port)) + if port == "Gi1/0/48": + continue + if self.isTrunk(port): + continue if not mac in self.macs: self.macs.append(mac) if not vlan in self.vlans: @@ -53,7 +59,11 @@ def parseMAC(self): # this function takes file target and loads it into the parse field def parseFile(self, target): - self.name = target.split(' ')[1].split('.')[0] + try: + self.name = target.split(' ')[1].split('.')[0] + except: + self.name = target.split('.')[0] + print("PARSED") self.parse = CiscoConfParse(target) parse_interfaces = self.parse.find_objects('^interface ') self.length = str(len(parse_interfaces))