Praktisch netwerkproblemen oplossen met automatisering
Binnen aaZoo werken we volgens het principe: als iets te automatiseren valt dan moet het geautomatiseerd worden. Automatiseren heeft namelijk als voordeel dat je repetitieve taken kunt vervangen door scripts waardoor de kans op fouten afneemt en configuraties altijd gelijk zijn en voldoen aan je standaarden.
Automatiseren kun je ook heel goed gebruiken om realtime data uit het netwerk te gebruiken om netwerkproblemen te voorkomen. In deze blog wil ik dit duidelijk te maken door een case uit de praktijk te behandelen.
Probleem access points
Vorig jaar hebben we het beheer over een netwerk overgenomen van een bedrijf met ongeveer 50 vestigingen. Tijdens het insourcen van dit netwerk hebben we alle switches en access points vervangen. In totaal gaat het in deze omgeving om 150 switches en zo’n 850 access points verspreid over de vestigingen. Tijdens de migratiefase werden we geconfronteerd met een lastig probleem: de installateur plaatste de access points voordat we een vestiging in beheer namen. In de meeste gevallen ging dit goed, maar op de plekken waar een of meerdere extra access points geplaatst werden ten opzichte van de oude situatie werd bestaande bekabeling gebruikt. Soms waren deze kabels reeds gepatched in de bestaande switches. Het probleem waar je dan tegenaan loopt is dat de access points een verkeerde switchpoort-configuratie hebben. De access points starten dan wel en gaan de netwerken uitzenden, maar omdat de switchpoort niet juist is geconfigureerd loopt het verkeer van de verbonden clients dood. Het is niet te doen om continu 850 access points in de gaten te houden, dus dit was een prima kandidaat om weg te automatiseren.
Oplossing: geautomatiseerd script
De oplossing voor dit probleem: een script dat verbindt met de Meraki API, van alle access points de management IP-adressen opvraagt en zodra een access point niet in het juiste subnet zit, de LLDP neighbour informatie opvraagt, zodat je weet op welke switch en poort het access point is aangesloten.
Het script
Het script is geschreven in Python en heeft de modules Requests en JSON nodig.
We starten met de header om het uitvoerbaar te maken en de modules te importeren. Ook schrijven we in de header een kort commentaar om duidelijk te maken waar het script voor dient:
#!/usr/bin/env python
# Lees de APs uit en alert als er geen 222 in het 3e octet voorkomt
#
import requests
import json
Vervolgens definiëren we een aantal variabelen die we verder gebruiken:
Als eerste de API-key, als je deze nog niet hebt kun je deze aanmaken in het Meraki dashboard. Zet onder de Organization Settings de optie ‘Dashboard API access’ aan. Vervolgens kun je onder je Meraki-gebruikersprofiel een API-key genereren.
meraki_apikey = ""
Daarna de Base URL, oftewel het eerste deel van de URL van de API waar we tegenaan communiceren.
meraki_baseurl = “https://api.meraki.com/api/v0”
Vervolgens het organisatie ID, deze vindt je via deze URL: https://dashboard.meraki.com/api/v0/organizations
meraki_organization = ""
Vervolgens bouwen we een aantal functies, deze heb ik gebaseerd op voorbeeld code van Cisco.
Als eerste een functie om de netwerken binnen een organisatie op te vragen, deze hebben we nodig om door de netwerken heen te kunnen lopen.
def getNetworks():
meraki_uri = "/organizations/" + meraki_organization + "/networks"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de netwerken.\n")
print(e)
sys.exit(1)
return response.json()
Vervolgens een functie om de access points binnen een netwerk op te vragen, deze functie heeft vereist als parameter het ID van een netwerk.
def getAPs(network_id):
meraki_uri = "/networks/" + network_id + "/devices"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de access-point informatie.\n")
print(e)
sys.exit(1)
return response.json()
En als derde functie eentje die de LLDP informatie van het access-point opvraagt. Deze functie vereist als parameter het netwerk ID van het netwerk waar het om gaat en het serienummer van het apparaat welke we bevragen.
def getLLDPinfo(network_id, serial):
meraki_uri = "/networks/" + network_id + "/devices/" + serial + "/lldp_cdp?timespan=7200"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de LLDP informatie.\n")
print(e)
sys.exit(1)
return response.json()
En uiteindelijk stellen we het script samen met de hoofdcode.
# Vraag netwerken op.
result = getNetworks()
# Loop door de netwerken heen.
for i in result:
# Vraag een lijst met access-points op uit het netwerk.
net_aps = getAPs(i['id'])
# Loop door de geretourneerde access-points heen.
for j in net_aps:
# Controleer of het om een access-point gaat.
if j['model'].startswith('MR'):
# Als het access-point een LAN IP adres heeft vraag deze dan op.
if j['lanIp']:
lanipje = str(j['lanIp'])
# Controleer of het IP van het access-point binnen het Management VLAN valt, zo niet doe dan de onderstaande acties.
if not '222' in lanipje:
# Print netwerknaam.
print("Netwerk:" + i['name'])
# Haal LLDP informatie op.
lldp_info = getLLDPinfo(i['id'],j['serial'])
# Print access-point naam, IP adres, naam van de switch waar deze op aangesloten zit en poortnummer.
print("AP: " + j['name'] + " IP: " + j['lanIp'] + " Switch: " + lldp_info['ports']['wired0']['lldp']['systemName'] + " Poort: " + lldp_info['ports']['wired0']['lldp']['portId'])
De Meraki API leent zich uitstekend voor het oplossen van dit soort problemen omdat de informatie reeds aanwezig is in de cloud database. Door dit script elke 15 minuten uit te voeren hebben we er voor gezorgd dat er vrijwel geen clients verbinding hebben gemaakt met een onjuist werkend access point tijdens de migratie.
Ik hoop dat ik met dit artikel je een beetje heb kunnen overtuigen van het nut van automatiseren in netwerkomgevingen en misschien wel heb geïnspireerd om zelf aan de slag te gaan. Mocht je hier interesse in hebben dan kan ik de volgende resources aanraden:
- Cisco DevNet StartNow, een leeromgeving over netwerkautomatisering: https://developer.cisco.com/startnow
- DevNet Sandbox, een sandbox omgeving om je scripts te ontwikkelen en testen: https://developer.cisco.com/site/sandbox/
- Kirk Byers uitstekende training, Python for Network Engineers: https://pynet.twb-tech.com/
Of neem voor meer informatie contact met ons op.
#!/usr/bin/env python
# Lees de APs uit en alert als er geen 222 in het 3e octet voorkomt
#
import json
meraki_apikey = ""
meraki_baseurl = "https://api.meraki.com/api/v0"
meraki_organization = ""
def getNetworks():
meraki_uri = "/organizations/" + meraki_organization + "/networks"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de netwerken.\n")
print(e)
sys.exit(1)
return response.json()
codemeraki_uri = "/networks/" + network_id + "/devices"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de access-point informatie.\n")
print(e)
sys.exit(1)Klik hier voor het volledige script
return response.json()
codemeraki_uri = "/networks/" + network_id + "/devices/" + serial + "/lldp_cdp?timespan=7200"
api_call = meraki_baseurl + meraki_uri
api_headers = {"X-Cisco-Meraki-API-Key": meraki_apikey}
session = requests.Session()
session.headers.update(api_headers)
try:
response = session.get(api_call,headers={"Content-Type": "application/json"})
except session.exceptions.RequestException as e:
print("ALLES KAPOT! Er is een fout opgetreden bij het opvragen van de LLDP informatie.\n")
print(e)
sys.exit(1)
return response.json()
# Vraag netwerken op.
result = getNetworks()
# Loop door de netwerken heen.
for i in result:
# Vraag een lijst met access-points op uit het netwerk.
net_aps = getAPs(i['id'])
# Loop door de geretourneerde access-points heen.
for j in net_aps:
# Controleer of het om een access-point gaat.
if j['model'].startswith('MR'):
# Als het access-point een LAN IP adres heeft vraag deze dan op.
if j['lanIp']:
lanipje = str(j['lanIp'])
# Controleer of het IP van het access-point binnen het Management VLAN valt, zo niet doe dan de onderstaande acties.
if not '222' in lanipje:
# Print netwerknaam.
print("Netwerk:" + i['name'])
# Haal LLDP informatie op.
lldp_info = getLLDPinfo(i['id'],j['serial'])
# Print access-point naam, IP adres, naam van de switch waar deze op aangesloten zit en poortnummer.
print("AP: " + j['name'] + " IP: " + j['lanIp'] + " Switch: " + lldp_info['ports']['wired0']['lldp']['systemName'] + " Poort: " + lldp_info['ports']['wired0']['lldp']['portId'])