-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterface_find_transceiver.py
executable file
·328 lines (297 loc) · 10.5 KB
/
interface_find_transceiver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
#!/usr/bin/env python3
"""
Name: interface_find_transceiver.py
Description: NXAPI: Find transceivers across one or more switches, using a variety of search terms
Example output:
Searching for substring in --name:
% ./interface_find_transceiver.py --vault hashicorp --devices cvd_leaf_1 --name CISCO
ip hostname interface serial_num search_term value
192.168.11.102 cvd-1311-leaf Ethernet1/9 APF20170506-CH1 name CISCO-AMPHENOL
192.168.11.102 cvd-1311-leaf Ethernet1/11 A4Z2103K1Y9-B name CISCO-AVAGO
192.168.11.102 cvd-1311-leaf Ethernet1/12 A4Z2103K1Y7-A name CISCO-AVAGO
192.168.11.102 cvd-1311-leaf Ethernet1/49 FIW202102SX-B name CISCO-FINISAR
etc...
%
Searching multiple switches for substring in --serialnum
% ./interface_find_transceiver.py --vault hashicorp --devices cvd_leaf_1,cvd_leaf_2,cvd_leaf_3,cvd_leaf_4 --serialnum FIW2229030N
ip hostname interface serial_num search_term value
192.168.11.104 cvd-1313-leaf Ethernet1/11 FIW2229030N-A serialnum FIW2229030N-A
--
%
Searching for substring in --type
% ./interface_find_transceiver.py --vault hashicorp --devices cvd_leaf_1 --type 100G
ip hostname interface serial_num search_term value
192.168.11.102 cvd-1311-leaf Ethernet1/49 FIW202102SX-B type QSFP-100G-AOC1M
192.168.11.102 cvd-1311-leaf Ethernet1/50 FIW202003MS-B type QSFP-100G-AOC1M
192.168.11.102 cvd-1311-leaf Ethernet1/51 FIW202102TE-A type QSFP-100G-AOC1M
192.168.11.102 cvd-1311-leaf Ethernet1/52 FIW202005PW-B type QSFP-100G-AOC1M
--
scripts %
"""
our_version = 102
script_name = "interface_find_transceiver"
# standard libraries
import argparse
from concurrent.futures import ThreadPoolExecutor
# local libraries
from nxapi_netbox.args.args_cookie import ArgsCookie
from nxapi_netbox.args.args_nxapi_tools import ArgsNxapiTools
from nxapi_netbox.general.log import get_logger
from nxapi_netbox.netbox.netbox_session import netbox, get_device_mgmt_ip
from nxapi_netbox.vault.vault import get_vault
from nxapi_netbox.nxapi.nxapi_interface_transceiver import NxapiInterfaceTransceiver
def get_parser():
help_ciscoid = "str() Search for substring in ciscoid"
help_ciscoid_1 = "str() Search for substring in ciscoid_1"
help_cisco_part_number = "str() Search for substring in cisco_part_number"
help_cisco_product_id = "str() Search for substring in cisco_product_id"
help_cisco_vendor_id = "str() Search for substring in cisco_vendor_id"
help_name = "str() Search for substring in name"
help_nom_bitrate = "int() Search for bitrate <= nom_bitrate"
help_partnum = "str() Search for substring in partnum"
help_rev = "str() Search for substring in rev"
help_serialnum = "str() Search for substring in serialnum"
help_type = "str() Search for substring in type"
ex = "Example: "
ex_ciscoid = "{} --ciscoid 17"
ex_ciscoid_1 = "{} --ciscoid_1 220"
ex_cisco_part_number = "{} --cisco_part_number 10-3172-01"
ex_cisco_product_id = "{} --cisco_product_id QSFP"
ex_cisco_vendor_id = "{} --cisco_vendor_id V01"
ex_name = "{} --name FINISAR"
ex_nom_bitrate = "{} --nom_bitrate 25500"
ex_partnum = "{} --partnum FTCL4352RH"
ex_rev = "{} --rev D"
ex_serialnum = "{} --serialnum FIW201014ZC"
ex_type = "{} --type QSFP"
parser = argparse.ArgumentParser(
description="DESCRIPTION: NXAPI: Find transceivers across one or more switches, using a variety of search terms",
parents=[ArgsCookie, ArgsNxapiTools],
)
default = parser.add_argument_group(title="DEFAULT SCRIPT ARGS")
mandatory = parser.add_argument_group(title="MANDATORY SCRIPT ARGS")
# Below, we set default to a string that is very unlikely to appear as a value
# for any field in 'show interface transceiver'. This needs to be a str(),
# rather than bool() or none() since we are checking if it's a substring of
# the field value.
default.add_argument(
"--ciscoid",
dest="ciscoid",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_ciscoid, ex_ciscoid),
)
default.add_argument(
"--ciscoid_1",
dest="ciscoid_1",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_ciscoid_1, ex_ciscoid_1),
)
default.add_argument(
"--cisco_part_number",
dest="cisco_part_number",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_cisco_part_number, ex_cisco_part_number),
)
default.add_argument(
"--cisco_product_id",
dest="cisco_product_id",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_cisco_product_id, ex_cisco_product_id),
)
default.add_argument(
"--cisco_vendor_id",
dest="cisco_vendor_id",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_cisco_vendor_id, ex_cisco_vendor_id),
)
default.add_argument(
"--name",
dest="name",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_name, ex_name),
)
default.add_argument(
"--nom_bitrate",
dest="nom_bitrate",
required=False,
default=-1,
help="{} {}".format(help_nom_bitrate, ex_nom_bitrate),
)
default.add_argument(
"--partnum",
dest="partnum",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_partnum, ex_partnum),
)
default.add_argument(
"--rev",
dest="rev",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_rev, ex_rev),
)
default.add_argument(
"--serialnum",
dest="serialnum",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_serialnum, ex_serialnum),
)
default.add_argument(
"--type",
dest="type",
required=False,
default="xxxxxxxxxxxxxxxx",
help="{} {}".format(help_type, ex_type),
)
parser.add_argument(
"--version", action="version", version="%(prog)s " + str(our_version)
)
return parser.parse_args()
def get_device_list():
try:
return cfg.devices.split(",")
except:
log.error(
"exiting. Cannot parse --devices {}. Example usage: --devices leaf_1,spine_2,leaf_2".format(
cfg.devices
)
)
exit(1)
def print_output(futures):
for future in futures:
output = future.result()
if output == None:
continue
for line in output:
print(line)
def print_header():
print(
fmt.format("ip", "hostname", "interface", "serial_num", "search_term", "value")
)
def search(ip, nx):
lines = list()
if cfg.ciscoid in nx.ciscoid:
lines.append(
fmt.format(
ip, nx.hostname, nx.interface, nx.serialnum, "ciscoid", nx.ciscoid
)
)
if cfg.ciscoid_1 in nx.ciscoid_1:
lines.append(
fmt.format(
ip, nx.hostname, nx.interface, nx.serialnum, "ciscoid_1", nx.ciscoid_1
)
)
if cfg.cisco_part_number in nx.cisco_part_number:
lines.append(
fmt.format(
ip,
nx.hostname,
nx.interface,
nx.serialnum,
"cisco_part_num",
nx.cisco_part_number,
)
)
if cfg.cisco_product_id in nx.cisco_product_id:
lines.append(
fmt.format(
ip,
nx.hostname,
nx.interface,
nx.serialnum,
"product_id",
nx.cisco_product_id,
)
)
if cfg.cisco_vendor_id in nx.cisco_vendor_id:
lines.append(
fmt.format(
ip,
nx.hostname,
nx.interface,
nx.serialnum,
"vendor_id",
nx.cisco_vendor_id,
)
)
if cfg.name in nx.name:
lines.append(
fmt.format(ip, nx.hostname, nx.interface, nx.serialnum, "name", nx.name)
)
try:
cfg_nom_bitrate = int(cfg.nom_bitrate)
except:
log.error(
"exiting. expected int() for --nom_bitrate, got {}".format(cfg.nom_bitrate)
)
exit(1)
if cfg_nom_bitrate >= nx.nom_bitrate:
lines.append(
fmt.format(
ip,
nx.hostname,
nx.interface,
nx.serialnum,
"nom_bitrate",
nx.nom_bitrate,
)
)
if cfg.partnum in nx.partnum:
lines.append(
fmt.format(
ip, nx.hostname, nx.interface, nx.serialnum, "partnum", nx.partnum
)
)
if cfg.rev in nx.rev:
lines.append(
fmt.format(ip, nx.hostname, nx.interface, nx.serialnum, "rev", nx.rev)
)
if cfg.serialnum in nx.serialnum:
lines.append(
fmt.format(
ip, nx.hostname, nx.interface, nx.serialnum, "serialnum", nx.serialnum
)
)
if cfg.type in nx.sfp_type:
lines.append(
fmt.format(ip, nx.hostname, nx.interface, nx.serialnum, "type", nx.sfp_type)
)
return lines
def find_transceivers(ip, nx):
lines = list()
for interface in nx.interfaces:
nx.interface = interface
lines += search(ip, nx)
return lines
def worker(device, vault):
ip = get_device_mgmt_ip(nb, device)
nx = NxapiInterfaceTransceiver(vault.nxos_username, vault.nxos_password, ip, log)
nx.nxapi_init(cfg)
nx.refresh()
lines = find_transceivers(ip, nx)
if len(lines) > 0:
lines.append("--")
return lines
fmt = "{:<15} {:<20} {:<20} {:<20} {:<11} {}"
cfg = get_parser()
log = get_logger(script_name, cfg.loglevel, "DEBUG")
vault = get_vault(cfg.vault)
vault.fetch_data()
nb = netbox(vault)
devices = get_device_list()
print_header()
executor = ThreadPoolExecutor(max_workers=len(devices))
futures = list()
for device in devices:
args = [device, vault]
futures.append(executor.submit(worker, *args))
print_output(futures)