Skip to content

Commit da51249

Browse files
committed
Adding support for additional interface detail, per request in #1. This is displayed in the Switch detail page > Port detail tab.
1 parent d18f098 commit da51249

8 files changed

+335
-176
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,5 @@ Example of the switch detail page:
5656
Example of the network-wide aggregate stats:
5757

5858
<p align="center">
59-
<img src="https://github.com/0x2142/switchport-web-dashboard/blob/main/screenshots/dasboard-aggregate-example.PNG"></img>
59+
<img src="https://github.com/0x2142/switchport-web-dashboard/blob/main/screenshots/dashboard-aggregate-example.PNG"></img>
6060
</p>

data_collector.py

+84-71
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,15 @@
66
import switchdb
77

88

9+
910
def loadDevices():
1011
"""
1112
Load device inventory from config.yml
1213
"""
1314
print("Loading devices from config file...")
14-
with open("config.yml", 'r') as config:
15+
with open("config.yml", "r") as config:
1516
devicelist = yaml.full_load(config)
16-
return devicelist['Devices']
17+
return devicelist["Devices"]
1718

1819

1920
def connectToDevice(deviceconfig):
@@ -22,19 +23,19 @@ def connectToDevice(deviceconfig):
2223
"""
2324
print("Loading device configuration...")
2425
device = {}
25-
device['host'] = deviceconfig['address']
26-
device['auth_username'] = deviceconfig['username']
27-
device['auth_password'] = deviceconfig['password']
28-
device['auth_strict_key'] = False
29-
device['timeout_socket'] = 10
30-
device['timeout_ops'] = 10
26+
device["host"] = deviceconfig["address"]
27+
device["auth_username"] = deviceconfig["username"]
28+
device["auth_password"] = deviceconfig["password"]
29+
device["auth_strict_key"] = False
30+
device["timeout_socket"] = 10
31+
device["timeout_ops"] = 10
3132
try:
32-
device['port'] = deviceconfig['port']
33+
device["port"] = deviceconfig["port"]
3334
except KeyError:
3435
pass
35-
if deviceconfig['type'] == 'ios-xe':
36+
if deviceconfig["type"] == "ios-xe":
3637
conn = IOSXEDriver(**device)
37-
elif deviceconfig['type'] == 'nx-os':
38+
elif deviceconfig["type"] == "nx-os":
3839
conn = NXOSDriver(**device)
3940
try:
4041
print(f"Attempting connection to {device['host']}")
@@ -62,70 +63,79 @@ def getInterfaceInfo(device):
6263
# Parse raw CLI using Genie
6364
intdata = resp.genie_parse_output()
6465
interfaceStats = {
65-
'total_port': 0,
66-
'up_port': 0,
67-
'down_port': 0,
68-
'disabled_port': 0,
69-
'intop10m': 0,
70-
'intop100m': 0,
71-
'intop1g': 0,
72-
'intop10g': 0,
73-
'intop25g': 0,
74-
'intop40g': 0,
75-
'intop100g': 0,
76-
'intmedcop': 0,
77-
'intmedsfp': 0,
78-
'intmedvirtual': 0
66+
"total_port": 0,
67+
"up_port": 0,
68+
"down_port": 0,
69+
"disabled_port": 0,
70+
"intop10m": 0,
71+
"intop100m": 0,
72+
"intop1g": 0,
73+
"intop10g": 0,
74+
"intop25g": 0,
75+
"intop40g": 0,
76+
"intop100g": 0,
77+
"intmedcop": 0,
78+
"intmedsfp": 0,
79+
"intmedvirtual": 0,
7980
}
81+
# Init dict for detailed interface operational stat collection
82+
intDetailed = {}
8083
# Process each interface
8184
for iface in intdata:
8285
# Skip VLAN / PortChannel Interfaces
83-
if 'Ethernet' not in iface:
84-
print(f'found non-ethernet interface: {iface}')
86+
if "Ethernet" not in iface:
87+
print(f"found non-ethernet interface: {iface}")
8588
continue
86-
if 'GigabitEthernet0/0' in iface:
87-
print(f'found management interface: {iface}')
89+
if "GigabitEthernet0/0" in iface:
90+
print(f"found management interface: {iface}")
8891
continue
8992
print(f"Working on interface {iface}")
93+
# Collect detailed interface stats (name, oper status, description, MAC)
94+
intDetailed[iface] = {}
95+
intDetailed[iface]["oper_status"] = intdata[iface]["oper_status"]
96+
intDetailed[iface]["description"] = intdata[iface]["description"]
97+
intDetailed[iface]["phys_addr"] = intdata[iface]["phys_address"]
98+
intDetailed[iface]["oper_speed"] = intdata[iface]["port_speed"]
99+
intDetailed[iface]["oper_duplex"] = intdata[iface]["duplex_mode"]
90100
# Count all Ethernet interfaces
91-
interfaceStats['total_port'] += 1
101+
interfaceStats["total_port"] += 1
92102
# Count admin-down interfaces
93-
if not intdata[iface]['enabled']:
94-
interfaceStats['disabled_port'] += 1
103+
if not intdata[iface]["enabled"]:
104+
interfaceStats["disabled_port"] += 1
95105
# Count 'not connected' interfaces
96-
elif intdata[iface]['enabled'] and intdata[iface]['oper_status'] == 'down':
97-
interfaceStats['down_port'] += 1
106+
elif intdata[iface]["enabled"] and intdata[iface]["oper_status"] == "down":
107+
interfaceStats["down_port"] += 1
98108
# Count up / connected interfaces - Then collect current speeds
99-
elif intdata[iface]['enabled'] and intdata[iface]['oper_status'] == 'up':
100-
interfaceStats['up_port'] += 1
101-
speed = intdata[iface]['bandwidth']
109+
elif intdata[iface]["enabled"] and intdata[iface]["oper_status"] == "up":
110+
interfaceStats["up_port"] += 1
111+
speed = intdata[iface]["bandwidth"]
102112
if speed == 10_000:
103-
interfaceStats['intop10m'] += 1
113+
interfaceStats["intop10m"] += 1
104114
if speed == 100_000:
105-
interfaceStats['intop100m'] += 1
115+
interfaceStats["intop100m"] += 1
106116
if speed == 1_000_000:
107-
interfaceStats['intop1g'] += 1
117+
interfaceStats["intop1g"] += 1
108118
if speed == 10_000_000:
109-
interfaceStats['intop10g'] += 1
119+
interfaceStats["intop10g"] += 1
110120
if speed == 25_000_000:
111-
interfaceStats['intop25g'] += 1
121+
interfaceStats["intop25g"] += 1
112122
if speed == 40_000_000:
113-
interfaceStats['intop40g'] += 1
123+
interfaceStats["intop40g"] += 1
114124
if speed == 100_000_000:
115-
interfaceStats['intop100g'] += 1
125+
interfaceStats["intop100g"] += 1
116126
# Count number of interfaces by media type
117127
try:
118-
media = intdata[iface]['media_type']
119-
if '1000BaseTX' in media:
120-
interfaceStats['intmedcop'] += 1
121-
elif 'Virtual' in media:
122-
interfaceStats['intmedvirtual'] += 1
128+
media = intdata[iface]["media_type"]
129+
if "1000BaseTX" in media:
130+
interfaceStats["intmedcop"] += 1
131+
elif "Virtual" in media:
132+
interfaceStats["intmedvirtual"] += 1
123133
else:
124-
interfaceStats['intmedsfp'] += 1
134+
interfaceStats["intmedsfp"] += 1
125135
except KeyError:
126-
interfaceStats['intmedsfp'] += 1
136+
interfaceStats["intmedsfp"] += 1
127137
# When complete - return int stats list
128-
return interfaceStats
138+
return interfaceStats, intDetailed
129139

130140

131141
def save_raw_output(data):
@@ -134,10 +144,10 @@ def save_raw_output(data):
134144
output is stored.
135145
"""
136146
# Create local directory to store raw output
137-
if not os.path.exists('raw_output'):
138-
os.makedirs('raw_output')
147+
if not os.path.exists("raw_output"):
148+
os.makedirs("raw_output")
139149
# Dump port information to file
140-
with open(f'raw_output/{system_serial}.txt', 'w') as a:
150+
with open(f"raw_output/{system_serial}.txt", "w") as a:
141151
a.write(data.result)
142152

143153

@@ -150,11 +160,11 @@ def getSystemInfoXE(device):
150160
resp = device.send_command("show version")
151161
parsed = resp.genie_parse_output()
152162
sysinfo = {}
153-
sysinfo['serial'] = parsed['version']['chassis_sn']
154-
sysinfo['model'] = parsed['version']['chassis']
155-
sysinfo['sw_ver'] = parsed['version']['version']
163+
sysinfo["serial"] = parsed["version"]["chassis_sn"]
164+
sysinfo["model"] = parsed["version"]["chassis"]
165+
sysinfo["sw_ver"] = parsed["version"]["version"]
156166
global system_serial
157-
system_serial = sysinfo['serial']
167+
system_serial = sysinfo["serial"]
158168
return sysinfo
159169

160170

@@ -167,11 +177,11 @@ def getSystemInfoNX(device):
167177
resp = device.send_command("show version")
168178
parsed = resp.genie_parse_output()
169179
sysinfo = {}
170-
sysinfo['serial'] = parsed['platform']['hardware']['processor_board_id']
171-
sysinfo['model'] = parsed['platform']['hardware']['model']
172-
sysinfo['sw_ver'] = parsed['platform']['software']['system_version']
180+
sysinfo["serial"] = parsed["platform"]["hardware"]["processor_board_id"]
181+
sysinfo["model"] = parsed["platform"]["hardware"]["model"]
182+
sysinfo["sw_ver"] = parsed["platform"]["software"]["system_version"]
173183
global system_serial
174-
system_serial = sysinfo['serial']
184+
system_serial = sysinfo["serial"]
175185
return sysinfo
176186

177187

@@ -185,7 +195,7 @@ def addDeviceToDB(devicelist):
185195
# Compare between new config file - see what should be added/removed
186196
curswitches = swDB.getAllSummary()
187197
currentSwitches = [row[3] for row in curswitches]
188-
newSwitches = [devicelist[switch]['address'] for switch in devicelist]
198+
newSwitches = [devicelist[switch]["address"] for switch in devicelist]
189199
swRemove = set(currentSwitches).difference(newSwitches)
190200
swAdd = set(newSwitches).difference(currentSwitches)
191201
# If switches to remove, purge from the database
@@ -197,7 +207,7 @@ def addDeviceToDB(devicelist):
197207

198208
print("Adding devices to DB...")
199209
for switch in devicelist:
200-
switchIP = devicelist[switch]['address']
210+
switchIP = devicelist[switch]["address"]
201211
if switchIP in swAdd:
202212
print(f"Adding switch ({switch} / {switchIP}) to DB...")
203213
swDB.addSwitch(str(switch), str(switchIP))
@@ -206,7 +216,7 @@ def addDeviceToDB(devicelist):
206216
swDB.close()
207217

208218

209-
def updateDB(device, ip, sysinfo, portinfo):
219+
def updateDB(device, ip, sysinfo, portinfo, detailedinfo):
210220
"""
211221
Insert new system & port information
212222
into the database
@@ -216,6 +226,8 @@ def updateDB(device, ip, sysinfo, portinfo):
216226
swDB.updateSysInfo(device, ip, sysinfo)
217227
print(f"Updating port info for {device} in DB...")
218228
swDB.updatePorts(device, ip, portinfo)
229+
print(f"Updating detailed port info for {device} in DB...")
230+
swDB.updateInterfaceDetails(device, ip, sysinfo, detailedinfo)
219231
swDB.close()
220232

221233

@@ -250,7 +262,7 @@ def run():
250262
# Iterate through each device for processing
251263
for device in devicelist:
252264
dev = device
253-
ip = devicelist[device]['address']
265+
ip = devicelist[device]["address"]
254266
# Open device connection
255267
devcon = connectToDevice(devicelist[device])
256268
if devcon:
@@ -260,13 +272,14 @@ def run():
260272
sysinfo = getSystemInfoXE(devcon)
261273
if type(devcon) == NXOSDriver:
262274
sysinfo = getSystemInfoNX(devcon)
263-
portinfo = getInterfaceInfo(devcon)
275+
portinfo, detailedinfo = getInterfaceInfo(devcon)
264276
except Exception as e:
265-
print(f'ERROR: {e}')
277+
print(f"ERROR: {e}")
266278
updateCheckStatus(device, ip, False)
267279
continue
268280
# Update database with new info
269-
updateDB(dev, ip, sysinfo, portinfo)
281+
updateDB(dev, ip, sysinfo, portinfo, detailedinfo)
282+
# Update database with interface detail info
270283
# Update if check succeeeded
271284
updateCheckStatus(dev, ip, True)
272285
else:
@@ -276,5 +289,5 @@ def run():
276289
updateLastRun()
277290

278291

279-
if __name__ == '__main__':
292+
if __name__ == "__main__":
280293
run()

screenshots/dashboard-detail-example.PNG

100644100755
62 KB
Loading

0 commit comments

Comments
 (0)