nornir-collection 0.0.10__py3-none-any.whl → 0.0.12__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nornir_collection/cisco/configuration_management/utils.py +1 -1
- nornir_collection/netbox/{scan_prefixes_and_update_ip_addresses.py → update_prefixes_ip_addresses.py} +215 -85
- nornir_collection/netbox/utils.py +58 -0
- {nornir_collection-0.0.10.dist-info → nornir_collection-0.0.12.dist-info}/METADATA +3 -2
- {nornir_collection-0.0.10.dist-info → nornir_collection-0.0.12.dist-info}/RECORD +8 -8
- {nornir_collection-0.0.10.dist-info → nornir_collection-0.0.12.dist-info}/LICENSE +0 -0
- {nornir_collection-0.0.10.dist-info → nornir_collection-0.0.12.dist-info}/WHEEL +0 -0
- {nornir_collection-0.0.10.dist-info → nornir_collection-0.0.12.dist-info}/top_level.txt +0 -0
@@ -373,7 +373,7 @@ def init_args_for_netconf_cm() -> argparse.Namespace:
|
|
373
373
|
"--pre-check",
|
374
374
|
action="store_true",
|
375
375
|
default=False,
|
376
|
-
help="
|
376
|
+
help="enable the pre-configuration check (default: False)",
|
377
377
|
)
|
378
378
|
|
379
379
|
# Verify the provided arguments and print the custom argparse error message in case any error or wrong
|
@@ -5,6 +5,7 @@ IP address, and vlan information.
|
|
5
5
|
The Main function is intended to import and execute by other scripts.
|
6
6
|
"""
|
7
7
|
|
8
|
+
import os
|
8
9
|
import sys
|
9
10
|
import ipaddress
|
10
11
|
import urllib.parse
|
@@ -12,6 +13,7 @@ from typing import Callable, Literal, Union
|
|
12
13
|
from concurrent.futures import ThreadPoolExecutor
|
13
14
|
import requests
|
14
15
|
import nmap
|
16
|
+
from ipfabric import IPFClient
|
15
17
|
from nornir_collection.netbox.utils import (
|
16
18
|
get_nb_resources,
|
17
19
|
post_nb_resources,
|
@@ -114,6 +116,7 @@ def create_nb_response_result(
|
|
114
116
|
data: Union[dict, list],
|
115
117
|
task_text: str,
|
116
118
|
text: str,
|
119
|
+
ds: Literal["nmap", "ip-fabric"] = None,
|
117
120
|
) -> tuple:
|
118
121
|
"""
|
119
122
|
Verify the NetBox response and return the result.
|
@@ -143,14 +146,19 @@ def create_nb_response_result(
|
|
143
146
|
# Create a list of fields that have been updated
|
144
147
|
updated_fields = []
|
145
148
|
|
146
|
-
# If data is a list of ip addresses from a active scanned prefix
|
149
|
+
# If data is a list of ip addresses from a active scanned prefix of IP-Fabric
|
147
150
|
if nb_type in "ip" and isinstance(data, list):
|
148
151
|
# Create a list of ip addresses that have been updated
|
149
152
|
for ip in data:
|
150
153
|
address = ip["address"]
|
151
154
|
dns_name = ip["dns_name"] if "dns_name" in ip and ip["dns_name"] else "None"
|
152
|
-
|
153
|
-
|
155
|
+
if ds == "nmap":
|
156
|
+
ports = (
|
157
|
+
", ".join([str(p) for p in ip["ports"]]) if "ports" in ip and ip["ports"] else "None"
|
158
|
+
)
|
159
|
+
updated_fields.append(f"- {address} (DNS: {dns_name}, Ports: {ports})")
|
160
|
+
else:
|
161
|
+
updated_fields.append(f"- {address} (DNS: {dns_name})")
|
154
162
|
# If data is a dictionary containing the prefix or information vlan associated with a prefix
|
155
163
|
elif nb_type in ("ip", "vlan") and isinstance(data, dict):
|
156
164
|
# If the response json contains the key 'vid' the response is from a vlan and has no VRF
|
@@ -195,7 +203,9 @@ def create_nb_response_result(
|
|
195
203
|
return result, True
|
196
204
|
|
197
205
|
|
198
|
-
def create_nb_ip_payload(
|
206
|
+
def create_nb_ip_payload(
|
207
|
+
parent_prefix: dict, data: list, ds: Literal["nmap", "ip-fabric"] = None, desired_status: str = None
|
208
|
+
) -> dict:
|
199
209
|
"""
|
200
210
|
Create a NetBox REST API payload.
|
201
211
|
To add or delete IP addresses of an active scanned prefix or update the following fields:
|
@@ -220,22 +230,25 @@ def create_nb_ip_payload(parent_prefix: dict, data: list, desired_status: str =
|
|
220
230
|
# Add the 'id' if it exists (not needed for post requests)
|
221
231
|
if "id" in ip:
|
222
232
|
item["id"] = ip["id"]
|
223
|
-
# If desired_status is not None, the payload is for active scanned ip addresses
|
233
|
+
# If desired_status is not None, the payload is for active scanned ip addresses or IP-Fabric
|
224
234
|
if desired_status:
|
225
235
|
# Add the 'address' and 'status' to the payload
|
226
236
|
item["address"] = ip["address"]
|
227
237
|
item["status"] = desired_status
|
228
|
-
# If the ip address exists in the
|
229
|
-
|
238
|
+
# If the ip address exists in the datasource_ips list
|
239
|
+
datasource_ip = [x for x in parent_prefix["datasource_ips"] if x["address"] == ip["address"]]
|
230
240
|
# Add the 'dns_name'
|
231
|
-
item["dns_name"] =
|
232
|
-
#
|
233
|
-
if
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
241
|
+
item["dns_name"] = datasource_ip[0]["dns_name"] if datasource_ip else ""
|
242
|
+
# If it's a nmap scan format the 'ports' as a Markdown table and add the 'ports'
|
243
|
+
if ds == "nmap":
|
244
|
+
if datasource_ip and datasource_ip[0]["ports"]:
|
245
|
+
md = [["Port", "State", "Service"]]
|
246
|
+
md.extend(
|
247
|
+
[[f"{k}/tcp", v["state"], v["name"]] for k, v in datasource_ip[0]["ports"].items()]
|
248
|
+
)
|
249
|
+
item["custom_fields"] = {"ipaddress_ports": make_markdown_table(md)}
|
250
|
+
else:
|
251
|
+
item["custom_fields"] = {"ipaddress_ports": None}
|
239
252
|
# If the desired_status is None, the payload is for all ip addresses of a prefix
|
240
253
|
else:
|
241
254
|
# Add the 'vrf' to the payload
|
@@ -253,23 +266,10 @@ def create_nb_ip_payload(parent_prefix: dict, data: list, desired_status: str =
|
|
253
266
|
return payload
|
254
267
|
|
255
268
|
|
256
|
-
def
|
269
|
+
def nmap_scan_prefix(prefix: dict, result: list) -> tuple:
|
257
270
|
"""
|
258
|
-
|
259
|
-
This function can be used within a ThreadPoolExecutor.
|
260
|
-
|
261
|
-
Args:
|
262
|
-
nb_url (str): The URL of the NetBox instance.
|
263
|
-
prefix (dict): The prefix to scan and retrieve IP addresses for.
|
264
|
-
|
265
|
-
Returns:
|
266
|
-
tuple: A tuple containing the result list and the updated prefix dictionary.
|
271
|
+
TBD
|
267
272
|
"""
|
268
|
-
# Create list to collect the results
|
269
|
-
result = []
|
270
|
-
|
271
|
-
#### Scan the prefix with nmap ###########################################################################
|
272
|
-
|
273
273
|
# Get the prefix length from the prefix
|
274
274
|
prefixlen = ipaddress.ip_network(prefix["prefix"]).prefixlen
|
275
275
|
# Get the network and broadcast address of the prefix to exclude them from the nmap scan
|
@@ -282,7 +282,7 @@ def get_netbox_ip_addresses_and_scan_prefix(nb_url: str, prefix: dict) -> tuple:
|
|
282
282
|
nm = nmap.PortScanner()
|
283
283
|
nm.scan(hosts=prefix["prefix"], arguments=arguments, sudo=True)
|
284
284
|
if nm.all_hosts():
|
285
|
-
prefix["
|
285
|
+
prefix["datasource_ips"] = [
|
286
286
|
{
|
287
287
|
"address": f"{nm[host]['addresses']['ipv4']}/{prefixlen}",
|
288
288
|
"dns_name": nm[host]["hostnames"][0]["name"],
|
@@ -291,16 +291,96 @@ def get_netbox_ip_addresses_and_scan_prefix(nb_url: str, prefix: dict) -> tuple:
|
|
291
291
|
for host in nm.all_hosts()
|
292
292
|
]
|
293
293
|
else:
|
294
|
-
prefix["
|
294
|
+
prefix["datasource_ips"] = []
|
295
295
|
|
296
296
|
# Print the task result
|
297
297
|
text = f"Nmap Scan Prefix {prefix['prefix']} for active IP-Addresses"
|
298
298
|
result.append(
|
299
299
|
f"{task_result(text=text, changed=False, level_name='INFO')}\n"
|
300
300
|
+ f"'{text}' -> NetBoxResponse <Success: True>\n"
|
301
|
-
+ f"-> Nmap prefix scan ip-address count: {len(prefix['
|
301
|
+
+ f"-> Nmap prefix scan ip-address count: {len(prefix['datasource_ips'])}"
|
302
302
|
)
|
303
303
|
|
304
|
+
return result, prefix
|
305
|
+
|
306
|
+
|
307
|
+
def get_ipfabric_data_for_prefix(prefix: dict, result: list) -> tuple:
|
308
|
+
"""
|
309
|
+
TBD
|
310
|
+
"""
|
311
|
+
# Connect to IP-Fabric
|
312
|
+
ipf = IPFClient(
|
313
|
+
base_url=os.environ["IPF_URL"], auth=os.environ["IPF_TOKEN"], snapshot_id="$last", verify=False
|
314
|
+
)
|
315
|
+
|
316
|
+
# Get the prefix length from the prefix
|
317
|
+
prefixlen = ipaddress.ip_network(prefix["prefix"]).prefixlen
|
318
|
+
# Get all ip-addresses of the prefix from the IP-Fabric technology arp table
|
319
|
+
# Remove duplicate ip-addresses as the arp table can contain multiple entries for the same ip-address
|
320
|
+
filters = {"ip": ["cidr", prefix["prefix"]]}
|
321
|
+
all_ips = list(set([x["ip"] for x in ipf.technology.addressing.arp_table.all(filters=filters)]))
|
322
|
+
# Get all ip-addresses of the prefix from the IP-Fabric inventory hosts table
|
323
|
+
# Set the ip-address as key to access the dict easier later
|
324
|
+
columns = ["ip", "dnsName"]
|
325
|
+
host_ips = {
|
326
|
+
x["ip"]: x["dnsName"] or "" for x in ipf.inventory.hosts.all(filters=filters, columns=columns)
|
327
|
+
}
|
328
|
+
# Add a list of all ip-addresses and other details to prefix
|
329
|
+
prefix["datasource_ips"] = [
|
330
|
+
{
|
331
|
+
"address": f"{ip}/{prefixlen}",
|
332
|
+
"dns_name": host_ips[ip] if ip in host_ips.keys() else "",
|
333
|
+
"ports": {},
|
334
|
+
}
|
335
|
+
for ip in all_ips
|
336
|
+
]
|
337
|
+
|
338
|
+
# Print the task result
|
339
|
+
text = f"IP-Fabric Get Data for Prefix {prefix['prefix']} IP-Addresses"
|
340
|
+
result.append(
|
341
|
+
f"{task_result(text=text, changed=False, level_name='INFO')}\n"
|
342
|
+
+ f"'{text}' -> IPFResponse <Success: True>\n"
|
343
|
+
+ f"-> IP-Fabric prefix ip-address count: {len(prefix['datasource_ips'])}"
|
344
|
+
)
|
345
|
+
|
346
|
+
return result, prefix
|
347
|
+
|
348
|
+
|
349
|
+
def get_nb_ips_and_external_datasource(nb_url: str, prefix: dict, ds: Literal["nmap", "ip-fabric"]) -> tuple:
|
350
|
+
"""
|
351
|
+
Get NetBox IP addresses and scan a prefix with nmap or get the data from IP-Fabric.
|
352
|
+
This function can be used within a ThreadPoolExecutor.
|
353
|
+
|
354
|
+
Args:
|
355
|
+
nb_url (str): The URL of the NetBox instance.
|
356
|
+
prefix (dict): The prefix to scan and retrieve IP addresses for.
|
357
|
+
ds (Literal["nmap", "ip-fabric"]): The datasource to use for the IP addresses.
|
358
|
+
|
359
|
+
Returns:
|
360
|
+
tuple: A tuple containing the result list and the updated prefix dictionary.
|
361
|
+
"""
|
362
|
+
# Create list to collect the results
|
363
|
+
failed = False
|
364
|
+
result = []
|
365
|
+
|
366
|
+
# Get the ip-addresses of the prefix from the datasource
|
367
|
+
if ds == "nmap":
|
368
|
+
# Scan the prefix with nmap
|
369
|
+
result, prefix = nmap_scan_prefix(prefix=prefix, result=result)
|
370
|
+
elif ds == "ip-fabric":
|
371
|
+
# Get the ip-addresses from the IP-Fabric
|
372
|
+
result, prefix = get_ipfabric_data_for_prefix(prefix=prefix, result=result)
|
373
|
+
else:
|
374
|
+
# Invalid datasource
|
375
|
+
failed = True
|
376
|
+
text = f"Get NetBox IP-Addresses of Prefix {prefix['prefix']}"
|
377
|
+
result.append(
|
378
|
+
f"{task_result(text=text, changed=False, level_name='ERROR')}\n"
|
379
|
+
+ f"'{text}' -> NetBoxResponse <Success: True>\n"
|
380
|
+
+ f"-> Invalid Datasource '{ds}'\n"
|
381
|
+
)
|
382
|
+
return result, prefix, failed
|
383
|
+
|
304
384
|
#### Get NetBox ip-addresses ############################################################################
|
305
385
|
|
306
386
|
# Add a list of dicts (id & address) of all NetBox ip-addresses for prefix
|
@@ -346,7 +426,7 @@ def get_netbox_ip_addresses_and_scan_prefix(nb_url: str, prefix: dict) -> tuple:
|
|
346
426
|
+ f"-> Deprecated ip-address count: {len(prefix['deprecated_ips'])}",
|
347
427
|
)
|
348
428
|
|
349
|
-
return result, prefix
|
429
|
+
return result, prefix, failed
|
350
430
|
|
351
431
|
|
352
432
|
def create_ip_list(loop_list: list[dict], check_list: list[dict], is_in_both: bool) -> list[dict]:
|
@@ -379,7 +459,7 @@ def create_ip_list(loop_list: list[dict], check_list: list[dict], is_in_both: bo
|
|
379
459
|
return ip_list
|
380
460
|
|
381
461
|
|
382
|
-
def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
462
|
+
def update_discovered_ip_addresses(nb_url: str, prefix: dict, ds: Literal["nmap", "ip-fabric"]) -> tuple:
|
383
463
|
"""
|
384
464
|
Posts new auto-discovered IP addresses to NetBox.
|
385
465
|
|
@@ -396,12 +476,16 @@ def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
396
476
|
task_text = "Add Auto-Discovered IP-Addresses"
|
397
477
|
|
398
478
|
# Add nmap scan ip-addresses that are not in the existing ip-addresses dict
|
399
|
-
add_ips = create_ip_list(
|
479
|
+
add_ips = create_ip_list(
|
480
|
+
loop_list=prefix["datasource_ips"], check_list=prefix["all_ips"], is_in_both=False
|
481
|
+
)
|
400
482
|
|
401
483
|
# If ip-addresses have been found
|
402
484
|
if add_ips:
|
403
485
|
# Create the payload to create the ip-addresses
|
404
|
-
payload = create_nb_ip_payload(
|
486
|
+
payload = create_nb_ip_payload(
|
487
|
+
parent_prefix=prefix, data=add_ips, ds=ds, desired_status="auto_discovered"
|
488
|
+
)
|
405
489
|
# POST request to update the ip-addresses
|
406
490
|
resp = post_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
407
491
|
|
@@ -409,7 +493,7 @@ def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
409
493
|
text = "The following 'Auto-Discovered' ip-addresses had been added:"
|
410
494
|
# The function returns the result list and True if the response is successful else False
|
411
495
|
sub_result, sub_failed = create_nb_response_result(
|
412
|
-
resp=resp, nb_type="ip", data=add_ips, task_text=task_text, text=text
|
496
|
+
resp=resp, nb_type="ip", data=add_ips, ds=ds, task_text=task_text, text=text
|
413
497
|
)
|
414
498
|
if "Response Json:" in sub_result[0]:
|
415
499
|
sub_result[0] += f"\n** DEBUG **\nPayload:\n{payload}\nResponse:\n{resp.json()}\n** DEBUG **\n"
|
@@ -418,14 +502,14 @@ def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
418
502
|
|
419
503
|
# Update the ip-addresses with the status 'auto_discovered' that are part of the nmap scan list
|
420
504
|
update_ips = create_ip_list(
|
421
|
-
loop_list=prefix["discovered_ips"], check_list=prefix["
|
505
|
+
loop_list=prefix["discovered_ips"], check_list=prefix["datasource_ips"], is_in_both=True
|
422
506
|
)
|
423
507
|
|
424
508
|
# If ip-addresses have been found
|
425
509
|
if update_ips:
|
426
510
|
# Create the payload to create the ip-addresses
|
427
511
|
payload = create_nb_ip_payload(
|
428
|
-
parent_prefix=prefix, data=update_ips, desired_status="auto_discovered"
|
512
|
+
parent_prefix=prefix, data=update_ips, ds=ds, desired_status="auto_discovered"
|
429
513
|
)
|
430
514
|
# PATCH request to update the ip-addresses
|
431
515
|
resp = patch_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
@@ -434,7 +518,7 @@ def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
434
518
|
text = "The following 'Auto-Discovered' ip-addresses had been updated:"
|
435
519
|
# The function returns the result list and True if the response is successful else False
|
436
520
|
sub_result, sub_failed = create_nb_response_result(
|
437
|
-
resp=resp, nb_type="ip", data=update_ips, task_text=task_text, text=text
|
521
|
+
resp=resp, nb_type="ip", data=update_ips, ds=ds, task_text=task_text, text=text
|
438
522
|
)
|
439
523
|
result.extend(sub_result)
|
440
524
|
failed = True if sub_failed else failed
|
@@ -442,7 +526,9 @@ def update_discovered_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
442
526
|
return result, failed
|
443
527
|
|
444
528
|
|
445
|
-
def delete_inactive_auto_discovered_ip_addresses(
|
529
|
+
def delete_inactive_auto_discovered_ip_addresses(
|
530
|
+
nb_url: str, prefix: dict, ds: Literal["nmap", "ip-fabric"]
|
531
|
+
) -> tuple:
|
446
532
|
"""
|
447
533
|
Deletes inactive auto-discovered IP addresses from NetBox.
|
448
534
|
|
@@ -460,7 +546,7 @@ def delete_inactive_auto_discovered_ip_addresses(nb_url: str, prefix: dict) -> t
|
|
460
546
|
|
461
547
|
# Delete the ip-addresses with the status 'auto_discovered' that are not in the nmap scan list
|
462
548
|
delete_ips = create_ip_list(
|
463
|
-
loop_list=prefix["discovered_ips"], check_list=prefix["
|
549
|
+
loop_list=prefix["discovered_ips"], check_list=prefix["datasource_ips"], is_in_both=False
|
464
550
|
)
|
465
551
|
|
466
552
|
# If ip-addresses have been found
|
@@ -473,13 +559,13 @@ def delete_inactive_auto_discovered_ip_addresses(nb_url: str, prefix: dict) -> t
|
|
473
559
|
text = "The following 'Auto-Discovered' ip-addresses had been deleted:"
|
474
560
|
# The function returns the result list and True if the response is successful else False
|
475
561
|
result, failed = create_nb_response_result(
|
476
|
-
resp=resp, nb_type="ip", data=delete_ips, task_text=task_text, text=text
|
562
|
+
resp=resp, nb_type="ip", data=delete_ips, ds=ds, task_text=task_text, text=text
|
477
563
|
)
|
478
564
|
|
479
565
|
return result, failed
|
480
566
|
|
481
567
|
|
482
|
-
def update_reserved_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
568
|
+
def update_reserved_ip_addresses(nb_url: str, prefix: dict, ds: Literal["nmap", "ip-fabric"]) -> tuple:
|
483
569
|
"""
|
484
570
|
Updates the status of reserved IP addresses in NetBox if they are reachable by nmap.
|
485
571
|
|
@@ -497,13 +583,13 @@ def update_reserved_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
497
583
|
|
498
584
|
# Update the ip-addresses with the status 'reserved' that are part of the nmap scan list
|
499
585
|
update_ips = create_ip_list(
|
500
|
-
loop_list=prefix["reserved_ips"], check_list=prefix["
|
586
|
+
loop_list=prefix["reserved_ips"], check_list=prefix["datasource_ips"], is_in_both=True
|
501
587
|
)
|
502
588
|
|
503
589
|
# If ip-addresses have been found
|
504
590
|
if update_ips:
|
505
591
|
# Create the payload to update the ip-addresses
|
506
|
-
payload = create_nb_ip_payload(parent_prefix=prefix, data=update_ips, desired_status="active")
|
592
|
+
payload = create_nb_ip_payload(parent_prefix=prefix, data=update_ips, ds=ds, desired_status="active")
|
507
593
|
# PATCH request to update the ip-addresses
|
508
594
|
resp = patch_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
509
595
|
|
@@ -511,13 +597,13 @@ def update_reserved_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
511
597
|
text = "The following 'Reserved' ip-addresses had been set to status 'Active':"
|
512
598
|
# The function returns the result list and True if the response is successful else False
|
513
599
|
result, failed = create_nb_response_result(
|
514
|
-
resp=resp, nb_type="ip", data=update_ips, task_text=task_text, text=text
|
600
|
+
resp=resp, nb_type="ip", data=update_ips, ds=ds, task_text=task_text, text=text
|
515
601
|
)
|
516
602
|
|
517
603
|
return result, failed
|
518
604
|
|
519
605
|
|
520
|
-
def update_inactive_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
606
|
+
def update_inactive_ip_addresses(nb_url: str, prefix: dict, ds: Literal["nmap", "ip-fabric"]) -> tuple:
|
521
607
|
"""
|
522
608
|
Updates the status of inactive IP addresses in NetBox if they are reachable by nmap.
|
523
609
|
|
@@ -535,13 +621,15 @@ def update_inactive_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
535
621
|
|
536
622
|
# Update the ip-addresses with the status 'inactive' that are part of the nmap scan list
|
537
623
|
inactive_ips = create_ip_list(
|
538
|
-
loop_list=prefix["inactive_ips"], check_list=prefix["
|
624
|
+
loop_list=prefix["inactive_ips"], check_list=prefix["datasource_ips"], is_in_both=True
|
539
625
|
)
|
540
626
|
|
541
627
|
# If ip-addresses have been found
|
542
628
|
if inactive_ips:
|
543
629
|
# Create the payload to update the ip-addresses
|
544
|
-
payload = create_nb_ip_payload(
|
630
|
+
payload = create_nb_ip_payload(
|
631
|
+
parent_prefix=prefix, data=inactive_ips, ds=ds, desired_status="active"
|
632
|
+
)
|
545
633
|
# PATCH request to update the ip-addresses
|
546
634
|
resp = patch_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
547
635
|
|
@@ -549,13 +637,15 @@ def update_inactive_ip_addresses(nb_url: str, prefix: dict) -> tuple:
|
|
549
637
|
text = "The following 'Inactive' ip-addresses had been set to status 'Active':"
|
550
638
|
# The function returns the result list and True if the response is successful else False
|
551
639
|
result, failed = create_nb_response_result(
|
552
|
-
resp=resp, nb_type="ip", data=inactive_ips, task_text=task_text, text=text
|
640
|
+
resp=resp, nb_type="ip", data=inactive_ips, ds=ds, task_text=task_text, text=text
|
553
641
|
)
|
554
642
|
|
555
643
|
return result, failed
|
556
644
|
|
557
645
|
|
558
|
-
def update_active_ip_addresses(
|
646
|
+
def update_active_ip_addresses(
|
647
|
+
nb_url: str, prefix: dict, overwrite_active: list[str], ds: Literal["nmap", "ip-fabric"]
|
648
|
+
) -> tuple:
|
559
649
|
"""
|
560
650
|
Updates the status of active IP addresses in NetBox if they are not reachable by nmap.
|
561
651
|
|
@@ -573,13 +663,13 @@ def update_active_ip_addresses(nb_url: str, prefix: dict, overwrite_active: list
|
|
573
663
|
|
574
664
|
# Update the ip-addresses with the status 'active' that are part of the nmap scan list
|
575
665
|
active_ips = create_ip_list(
|
576
|
-
loop_list=prefix["active_ips"], check_list=prefix["
|
666
|
+
loop_list=prefix["active_ips"], check_list=prefix["datasource_ips"], is_in_both=True
|
577
667
|
)
|
578
668
|
|
579
669
|
# If ip-addresses have been found
|
580
670
|
if active_ips:
|
581
671
|
# Create the payload to update the ip-addresses
|
582
|
-
payload = create_nb_ip_payload(parent_prefix=prefix, data=active_ips, desired_status="active")
|
672
|
+
payload = create_nb_ip_payload(parent_prefix=prefix, data=active_ips, ds=ds, desired_status="active")
|
583
673
|
# PATCH request to update the ip-addresses
|
584
674
|
resp = patch_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
585
675
|
|
@@ -587,14 +677,14 @@ def update_active_ip_addresses(nb_url: str, prefix: dict, overwrite_active: list
|
|
587
677
|
text = "The following 'Active' ip-addresses had been updated:"
|
588
678
|
# The function returns the result list and True if the response is successful else False
|
589
679
|
sub_result, sub_failed = create_nb_response_result(
|
590
|
-
resp=resp, nb_type="ip", data=active_ips, task_text=task_text, text=text
|
680
|
+
resp=resp, nb_type="ip", data=active_ips, ds=ds, task_text=task_text, text=text
|
591
681
|
)
|
592
682
|
result.extend(sub_result)
|
593
683
|
failed = True if sub_failed else failed
|
594
684
|
|
595
685
|
# Update the ip-addresses with the status 'active' that are not part of the nmap scan list
|
596
686
|
inactive_ips = create_ip_list(
|
597
|
-
loop_list=prefix["active_ips"], check_list=prefix["
|
687
|
+
loop_list=prefix["active_ips"], check_list=prefix["datasource_ips"], is_in_both=False
|
598
688
|
)
|
599
689
|
# Create a new list to exclude the overwrite_active ip-addresses
|
600
690
|
inactive_ips = [ip for ip in inactive_ips if ip["address"] not in overwrite_active]
|
@@ -602,7 +692,9 @@ def update_active_ip_addresses(nb_url: str, prefix: dict, overwrite_active: list
|
|
602
692
|
# If ip-addresses have been found
|
603
693
|
if inactive_ips:
|
604
694
|
# Create the payload to update the ip-addresses
|
605
|
-
payload = create_nb_ip_payload(
|
695
|
+
payload = create_nb_ip_payload(
|
696
|
+
parent_prefix=prefix, data=inactive_ips, ds=ds, desired_status="inactive"
|
697
|
+
)
|
606
698
|
# PATCH request to update the ip-addresses
|
607
699
|
resp = patch_nb_resources(url=f"{nb_url}/api/ipam/ip-addresses/", payload=payload)
|
608
700
|
|
@@ -610,7 +702,7 @@ def update_active_ip_addresses(nb_url: str, prefix: dict, overwrite_active: list
|
|
610
702
|
text = "The following 'Active' ip-addresses had been set to status 'Inactive':"
|
611
703
|
# The function returns the result list and True if the response is successful else False
|
612
704
|
sub_result, sub_failed = create_nb_response_result(
|
613
|
-
resp=resp, nb_type="ip", data=inactive_ips, task_text=task_text, text=text
|
705
|
+
resp=resp, nb_type="ip", data=inactive_ips, ds=ds, task_text=task_text, text=text
|
614
706
|
)
|
615
707
|
result.extend(sub_result)
|
616
708
|
failed = True if sub_failed else failed
|
@@ -639,7 +731,7 @@ def set_results_changed_failed(results, result, changed, sub_failed, failed) ->
|
|
639
731
|
return results, changed, failed
|
640
732
|
|
641
733
|
|
642
|
-
def
|
734
|
+
def update_netbox_prefix_ip_addresses(prefix: list, *args) -> tuple:
|
643
735
|
"""
|
644
736
|
This function can be used within a ThreadPoolExecutor. Update the IP addresses of a active NetBox prefix
|
645
737
|
with the following information:
|
@@ -656,9 +748,10 @@ def update_active_netbox_prefix_ip_addresses(prefix: list, *overwrite_active) ->
|
|
656
748
|
"""
|
657
749
|
# Create a list to collect the task results
|
658
750
|
results = []
|
659
|
-
#
|
660
|
-
|
661
|
-
|
751
|
+
# Set the datasource by the first arg ('namp' or 'ip-fabric') and make sure its a string
|
752
|
+
ds = str(args[0])
|
753
|
+
# Set the ip-address list to overwrite the status as active by the second arg and make sure its a list
|
754
|
+
overwrite_active = list(args[1])
|
662
755
|
# Boolian to check if any ip-addresses have been changed and the overall failed status
|
663
756
|
changed = False
|
664
757
|
failed = False
|
@@ -669,29 +762,31 @@ def update_active_netbox_prefix_ip_addresses(prefix: list, *overwrite_active) ->
|
|
669
762
|
# Get the base url of the NetBox instance
|
670
763
|
nb_url = base_url(url=prefix["url"], with_path=False)
|
671
764
|
|
672
|
-
#
|
673
|
-
result, prefix =
|
765
|
+
# Scan the prefix with nmap and add the list to the prefix dict or get the ip-addresses from IP-Fabric
|
766
|
+
result, prefix, failed = get_nb_ips_and_external_datasource(nb_url=nb_url, prefix=prefix, ds=ds)
|
674
767
|
results.extend(result)
|
768
|
+
if failed:
|
769
|
+
return results, failed
|
675
770
|
|
676
771
|
# Add new 'auto-discovered' ip-addresses
|
677
|
-
result, sub_failed = update_discovered_ip_addresses(nb_url=nb_url, prefix=prefix)
|
772
|
+
result, sub_failed = update_discovered_ip_addresses(nb_url=nb_url, prefix=prefix, ds=ds)
|
678
773
|
results, changed, failed = set_results_changed_failed(results, result, changed, sub_failed, failed)
|
679
774
|
|
680
775
|
# Delete inactive 'auto-discovered' ip-addresses
|
681
|
-
result, sub_failed = delete_inactive_auto_discovered_ip_addresses(nb_url=nb_url, prefix=prefix)
|
776
|
+
result, sub_failed = delete_inactive_auto_discovered_ip_addresses(nb_url=nb_url, prefix=prefix, ds=ds)
|
682
777
|
results, changed, failed = set_results_changed_failed(results, result, changed, sub_failed, failed)
|
683
778
|
|
684
779
|
# Update 'reserved' ip-addresses -> set status to 'active'
|
685
|
-
result, sub_failed = update_reserved_ip_addresses(nb_url=nb_url, prefix=prefix)
|
780
|
+
result, sub_failed = update_reserved_ip_addresses(nb_url=nb_url, prefix=prefix, ds=ds)
|
686
781
|
results, changed, failed = set_results_changed_failed(results, result, changed, sub_failed, failed)
|
687
782
|
|
688
783
|
# Update 'inactive' ip-addresses -> set status to 'active'
|
689
|
-
result, sub_failed = update_inactive_ip_addresses(nb_url=nb_url, prefix=prefix)
|
784
|
+
result, sub_failed = update_inactive_ip_addresses(nb_url=nb_url, prefix=prefix, ds=ds)
|
690
785
|
results, changed, failed = set_results_changed_failed(results, result, changed, sub_failed, failed)
|
691
786
|
|
692
787
|
# Update 'active' ip-addresses -> set status to 'active' or 'inactive'
|
693
788
|
result, sub_failed = update_active_ip_addresses(
|
694
|
-
nb_url=nb_url, prefix=prefix, overwrite_active=overwrite_active
|
789
|
+
nb_url=nb_url, prefix=prefix, overwrite_active=overwrite_active, ds=ds
|
695
790
|
)
|
696
791
|
results, changed, failed = set_results_changed_failed(results, result, changed, sub_failed, failed)
|
697
792
|
|
@@ -816,7 +911,9 @@ def update_all_netbox_vlans(vlan: dict) -> tuple:
|
|
816
911
|
return results, failed
|
817
912
|
|
818
913
|
|
819
|
-
def run_thread_pool(
|
914
|
+
def run_thread_pool(
|
915
|
+
title: str, task: Callable, thread_list: list[dict], max_workers: int = 50, args: tuple = ()
|
916
|
+
) -> list:
|
820
917
|
"""
|
821
918
|
Runs a thread pool with a given task for each item in the thread list.
|
822
919
|
|
@@ -843,7 +940,7 @@ def run_thread_pool(title: str, task: Callable, thread_list: list[dict], args: t
|
|
843
940
|
return []
|
844
941
|
|
845
942
|
# Create a ThreadPoolExecutor
|
846
|
-
with ThreadPoolExecutor(max_workers=
|
943
|
+
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
847
944
|
# Submit a new task for each prefix to update and collect the tasks results
|
848
945
|
threads = [executor.submit(task, item, *args) for item in thread_list]
|
849
946
|
|
@@ -881,7 +978,7 @@ def print_thread_pool_results(title: str, thread_result, fail_hard: bool = False
|
|
881
978
|
return failed_task
|
882
979
|
|
883
980
|
|
884
|
-
def main(nr_config: str, overwrite_active: list[str] = None) -> None:
|
981
|
+
def main(nr_config: str, nmap_scan: bool = False, overwrite_active: list[str] = None) -> None:
|
885
982
|
"""
|
886
983
|
Main function is intended to import and execute by other scripts.
|
887
984
|
It loads NetBox inventory, scan active prefixes, and update IP addresses and VLANs.
|
@@ -918,11 +1015,20 @@ def main(nr_config: str, overwrite_active: list[str] = None) -> None:
|
|
918
1015
|
# Get the NetBox URL (Authentication token will be loaded as nb_token env variable)
|
919
1016
|
nb_url = nr_config_dict["inventory"]["options"]["nb_url"]
|
920
1017
|
|
921
|
-
# Load Active NetBox Prefixes
|
922
|
-
|
923
|
-
|
1018
|
+
# Load Active NetBox Prefixes from Tenant 'none', 'oob', 'tier-1' and 'tier-2'
|
1019
|
+
# These prefixes will be scanned with nmap and updated
|
1020
|
+
nb_active_oob_t1_t2_prefixes = load_netbox_data(
|
1021
|
+
task_text="Load Active OOB/T1/T2 NetBox Prefixes",
|
1022
|
+
nb_api_url=f"{nb_url}/api/ipam/prefixes/",
|
1023
|
+
query={"status": "active", "tenant": ["none", "oob", "tier-1", "tier-2"], "mark_utilized": "false"},
|
1024
|
+
)
|
1025
|
+
|
1026
|
+
# Load Active/Inventory NetBox Prefixes from Tenant 'tier-3' and 'tier-4'
|
1027
|
+
# These prefixes will be updated with input from IP-Fabric
|
1028
|
+
nb_active_inventory_t3_t4_prefixes = load_netbox_data(
|
1029
|
+
task_text="Load Active & Inventory T3/T4 NetBox Prefixes",
|
924
1030
|
nb_api_url=f"{nb_url}/api/ipam/prefixes/",
|
925
|
-
query={"status": "active", "mark_utilized": "false"},
|
1031
|
+
query={"status": ["active", "inventory"], "tenant": ["tier-3", "tier-4"], "mark_utilized": "false"},
|
926
1032
|
)
|
927
1033
|
|
928
1034
|
# Load NetBox Non-Container Prefixes
|
@@ -940,20 +1046,42 @@ def main(nr_config: str, overwrite_active: list[str] = None) -> None:
|
|
940
1046
|
query={},
|
941
1047
|
)
|
942
1048
|
|
943
|
-
#### Scan Active NetBox Prefixes and Update IP-Addresses
|
1049
|
+
#### Nmap Scan Active NetBox Prefixes and Update IP-Addresses ###########################################
|
1050
|
+
|
1051
|
+
if nmap_scan:
|
1052
|
+
# Set the task title
|
1053
|
+
title = "Nmap Scan Active OOB/T1/T2 NetBox Prefixes and Update IP-Addresses"
|
1054
|
+
|
1055
|
+
# Run the thread pool to update all NetBox IP-Addresses Status and DNS-Name
|
1056
|
+
# 1. arg is the input type ('nmap' or 'ip-fabric')
|
1057
|
+
# 2. arg is the list of active IP addresses to overwrite
|
1058
|
+
thread_result = run_thread_pool(
|
1059
|
+
title=title,
|
1060
|
+
task=update_netbox_prefix_ip_addresses,
|
1061
|
+
thread_list=nb_active_oob_t1_t2_prefixes,
|
1062
|
+
max_workers=50,
|
1063
|
+
args=("nmap", overwrite_active),
|
1064
|
+
)
|
1065
|
+
# Print the thread pool results and exit the script if any task has failed
|
1066
|
+
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=True)
|
1067
|
+
|
1068
|
+
#### IP-Fabric Update Active & Inventory NetBox Prefixes IP-Addresses ###################################
|
944
1069
|
|
945
1070
|
# Set the task title
|
946
|
-
title = "
|
1071
|
+
title = "IP-Fabric Update Active & Inventory T3/T4 NetBox Prefixes IP-Addresses"
|
947
1072
|
|
948
1073
|
# Run the thread pool to update all NetBox IP-Addresses Status and DNS-Name
|
1074
|
+
# 1. arg is the input type ('nmap' or 'ip-fabric')
|
1075
|
+
# 2. arg is the list of active IP addresses to overwrite
|
949
1076
|
thread_result = run_thread_pool(
|
950
1077
|
title=title,
|
951
|
-
task=
|
952
|
-
thread_list=
|
953
|
-
|
1078
|
+
task=update_netbox_prefix_ip_addresses,
|
1079
|
+
thread_list=nb_active_inventory_t3_t4_prefixes,
|
1080
|
+
max_workers=10,
|
1081
|
+
args=("ip-fabric", overwrite_active),
|
954
1082
|
)
|
955
1083
|
# Print the thread pool results and exit the script if any task has failed
|
956
|
-
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=
|
1084
|
+
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=True)
|
957
1085
|
|
958
1086
|
#### Update all IP-Addresses Tags and other Fields ######################################################
|
959
1087
|
|
@@ -964,10 +1092,11 @@ def main(nr_config: str, overwrite_active: list[str] = None) -> None:
|
|
964
1092
|
thread_result = run_thread_pool(
|
965
1093
|
title=title,
|
966
1094
|
task=update_all_netbox_ip_addresses,
|
1095
|
+
max_workers=100,
|
967
1096
|
thread_list=nb_subnet_prefixes,
|
968
1097
|
)
|
969
1098
|
# Print the thread pool results and exit the script if any task has failed
|
970
|
-
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=
|
1099
|
+
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=True)
|
971
1100
|
|
972
1101
|
#### Update all VLANs Tags and other Fields #############################################################
|
973
1102
|
|
@@ -978,7 +1107,8 @@ def main(nr_config: str, overwrite_active: list[str] = None) -> None:
|
|
978
1107
|
thread_result = run_thread_pool(
|
979
1108
|
title=title,
|
980
1109
|
task=update_all_netbox_vlans,
|
1110
|
+
max_workers=100,
|
981
1111
|
thread_list=nb_vlans,
|
982
1112
|
)
|
983
1113
|
# Print the thread pool results and exit the script if any task has failed
|
984
|
-
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=
|
1114
|
+
print_thread_pool_results(title=title, thread_result=thread_result, fail_hard=True)
|
@@ -104,6 +104,64 @@ def init_args_for_nornir_config_filepath() -> str:
|
|
104
104
|
return nr_config
|
105
105
|
|
106
106
|
|
107
|
+
def init_args_for_ipam_update() -> str:
|
108
|
+
"""
|
109
|
+
This function initialze arguments to specify which NetBox instance and Nornir config filepath to use.
|
110
|
+
"""
|
111
|
+
task_text = "Argparse verify arguments"
|
112
|
+
print_task_name(text=task_text)
|
113
|
+
|
114
|
+
# Load environment variables or raise a TypeError when is None
|
115
|
+
env_vars = get_env_vars(envs=["NR_CONFIG_PROD", "NR_CONFIG_TEST"], task_text=task_text)
|
116
|
+
nr_config_prod = env_vars["NR_CONFIG_PROD"]
|
117
|
+
nr_config_test = env_vars["NR_CONFIG_TEST"]
|
118
|
+
|
119
|
+
# Define the arguments which needs to be given to the script execution
|
120
|
+
argparser = CustomArgParse(
|
121
|
+
prog=os.path.basename(__main__.__file__),
|
122
|
+
description="Specify the NetBox PROD or TEST instance and Nornir config filepath to be used",
|
123
|
+
epilog="One of the two mandatory arguments is required.",
|
124
|
+
argument_default=argparse.SUPPRESS,
|
125
|
+
formatter_class=CustomArgParseWidthFormatter,
|
126
|
+
)
|
127
|
+
# Add all NetBox arguments
|
128
|
+
argparser.add_argument(
|
129
|
+
"--prod",
|
130
|
+
action="store_true",
|
131
|
+
help=f"use the NetBox 'PROD' instance and Nornir config '{nr_config_prod}'",
|
132
|
+
)
|
133
|
+
argparser.add_argument(
|
134
|
+
"--test",
|
135
|
+
action="store_true",
|
136
|
+
help=f"use the NetBox 'TEST' instance and Nornir config '{nr_config_test}'",
|
137
|
+
)
|
138
|
+
# Add the optional rebuild argument
|
139
|
+
argparser.add_argument(
|
140
|
+
"--nmap",
|
141
|
+
action="store_true",
|
142
|
+
default=False,
|
143
|
+
help="enable additionally to IP-Fabric a NMAP scan (default: no NMAP scan)",
|
144
|
+
)
|
145
|
+
# Verify the provided arguments and print the custom argparse error message in case any error or wrong
|
146
|
+
# arguments are present and exit the script
|
147
|
+
args = argparser.parse_args()
|
148
|
+
|
149
|
+
# Verify the NetBox instance and Nornir config filepath
|
150
|
+
if not (hasattr(args, "prod") or hasattr(args, "test")):
|
151
|
+
argparser.error("No NetBox instance specified, add --prod or --test")
|
152
|
+
|
153
|
+
# Set the NetBox instance and the Nornir config file based on the arguments
|
154
|
+
nb_instance = "TEST" if args.test else "PROD"
|
155
|
+
nr_config = nr_config_test if args.test else nr_config_prod
|
156
|
+
|
157
|
+
# If argparser.parse_args() is successful -> no argparse error message
|
158
|
+
print(task_info(text=task_text, changed=False))
|
159
|
+
print(f"'{task_text}' -> ArgparseResponse <Success: True>")
|
160
|
+
print(f"-> Run on the NetBox '{nb_instance}' instance and Nornir config '{nr_config}'")
|
161
|
+
|
162
|
+
return nr_config, args
|
163
|
+
|
164
|
+
|
107
165
|
def get_nb_resources(url: str, params: Dict[str, Any] = {}) -> List[Dict[str, Any]]:
|
108
166
|
"""
|
109
167
|
TBD
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: nornir-collection
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.12
|
4
4
|
Summary: Nornir-Collection contains network automation functions and complete IaC workflows with Nornir and other python libraries. It contains Nornir tasks and general functions in Nornir style.
|
5
5
|
Author: Willi Kubny
|
6
6
|
Author-email: willi.kubny@gmail.ch
|
@@ -12,7 +12,7 @@ Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
13
13
|
Requires-Dist: nornir==3.3.0
|
14
14
|
Requires-Dist: nornir-jinja2==0.2.0
|
15
|
-
Requires-Dist: nornir-salt==0.
|
15
|
+
Requires-Dist: nornir-salt==0.22.2
|
16
16
|
Requires-Dist: nornir-netmiko==1.0.1
|
17
17
|
Requires-Dist: nornir-scrapli==2023.7.30
|
18
18
|
Requires-Dist: scrapli-netconf==2023.7.30
|
@@ -20,6 +20,7 @@ Requires-Dist: scrapli[ssh2]
|
|
20
20
|
Requires-Dist: scrapli[genie]
|
21
21
|
Requires-Dist: nornir-utils==0.2.0
|
22
22
|
Requires-Dist: pynetbox==7.4.0
|
23
|
+
Requires-Dist: ipfabric==7.0.2
|
23
24
|
Requires-Dist: py-pure-client==1.51.0
|
24
25
|
Requires-Dist: nornir-pyfgt==1.0.3
|
25
26
|
Requires-Dist: python-nmap==0.7.1
|
@@ -8,7 +8,7 @@ nornir_collection/cisco/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
8
8
|
nornir_collection/cisco/configuration_management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
9
9
|
nornir_collection/cisco/configuration_management/processor.py,sha256=KjhilyyDDiYL7wFemGEWSP16OLeM4dENmrtb20LRssY,6443
|
10
10
|
nornir_collection/cisco/configuration_management/pyats.py,sha256=j9XzG3ttURR0wtu2Se9QQEpG5o2kq9mqDkReNCdWKpk,8932
|
11
|
-
nornir_collection/cisco/configuration_management/utils.py,sha256=
|
11
|
+
nornir_collection/cisco/configuration_management/utils.py,sha256=X20A1G0MMlTt5VJ0mqRmqFlA_Bpi7_0FPKPJLaqoKNc,18632
|
12
12
|
nornir_collection/cisco/configuration_management/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
13
13
|
nornir_collection/cisco/configuration_management/cli/config_tasks.py,sha256=mWXysgUm6ymNLQjomB1T05QT9A-fdV1aEKFzzDrfCUw,22147
|
14
14
|
nornir_collection/cisco/configuration_management/cli/config_workflow.py,sha256=GIka5SPLZ7M2zCFv8Jadl73QC-InnGopzI8xQt36MfM,3459
|
@@ -36,14 +36,14 @@ nornir_collection/fortinet/utils.py,sha256=xkvxdJy3-aD39WK_9Gc0rY9r-OxfHnPVNMspy
|
|
36
36
|
nornir_collection/netbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
nornir_collection/netbox/custom_script.py,sha256=yU1lbv_25b3qAWA6GRsVYpEuh0KUPTVo47U5s_lksjo,4050
|
38
38
|
nornir_collection/netbox/inventory.py,sha256=2db5GogMsY5bZgc4mXIhlmH9pcvyQ7AE55dL0EiqxDI,15488
|
39
|
-
nornir_collection/netbox/scan_prefixes_and_update_ip_addresses.py,sha256=IGaE-HR_eManlENJzx7odn6yuMgpUV85NZfhpfaxpA0,41376
|
40
39
|
nornir_collection/netbox/set_device_status.py,sha256=vtn0KcR-91Z2aLjbEpZRef1Jip8eM9GWbKRiAJuEjLY,2437
|
41
40
|
nornir_collection/netbox/sync_datasource.py,sha256=eEsgwy_arIPbA-ObqqzTNdU9aiP80s7LCzAKA6hCXYQ,4703
|
42
41
|
nornir_collection/netbox/update_cisco_inventory_data.py,sha256=Aq4VGvAIiBhOCsSOF-wBUrpYtBXR8HwR3NCWEeM4d0g,6426
|
43
42
|
nornir_collection/netbox/update_cisco_support_plugin_data.py,sha256=H8SfqESad64LrZrsWOaICHKj122sgu96dK9RcbvtzGM,13896
|
44
43
|
nornir_collection/netbox/update_fortinet_inventory_data.py,sha256=ltwkE_bFljRUR4aeOxorChCsHdZciD1TqvoPnWTUIUg,6367
|
44
|
+
nornir_collection/netbox/update_prefixes_ip_addresses.py,sha256=Xn6qmD9AzT9S92QrKHNJNJZjcFvTgPhhSJ0EyqXum8s,46792
|
45
45
|
nornir_collection/netbox/update_purestorage_inventory_data.py,sha256=cGZNMTZWJ0wu1BYdE92EVN-C-oLMJHxaKi_-1cMg0Ow,5368
|
46
|
-
nornir_collection/netbox/utils.py,sha256=
|
46
|
+
nornir_collection/netbox/utils.py,sha256=Ubph1yUkYJq8H6Bjr4zczTSilfLWCrv9xekHhEYiUAM,11853
|
47
47
|
nornir_collection/netbox/verify_device_primary_ip.py,sha256=6UCdZaZxhV4v8KqpjSpE9c7jaxIAF2krrknrrRj1AvM,8690
|
48
48
|
nornir_collection/nornir_plugins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
49
49
|
nornir_collection/nornir_plugins/inventory/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -52,8 +52,8 @@ nornir_collection/nornir_plugins/inventory/staggered_yaml.py,sha256=nBvUFq7U5zVT
|
|
52
52
|
nornir_collection/nornir_plugins/inventory/utils.py,sha256=mxIlKK-4PHqCnFKn7Oozu1RW_JB5z1TgEYc-ave70nE,11822
|
53
53
|
nornir_collection/purestorage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
nornir_collection/purestorage/utils.py,sha256=TqU2sKz0ENnmSDEBcSvXPnVkI1DVHOogI68D7l32g7I,1730
|
55
|
-
nornir_collection-0.0.
|
56
|
-
nornir_collection-0.0.
|
57
|
-
nornir_collection-0.0.
|
58
|
-
nornir_collection-0.0.
|
59
|
-
nornir_collection-0.0.
|
55
|
+
nornir_collection-0.0.12.dist-info/LICENSE,sha256=bOPVh1OVNwz2tCjkLaChWT6AoXdtqye3aua5l0tgYJo,1068
|
56
|
+
nornir_collection-0.0.12.dist-info/METADATA,sha256=qlPqaGa7m6SOCW7nqPHQCnGltqKhsKaQ_4KsSWIO8r0,7169
|
57
|
+
nornir_collection-0.0.12.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
58
|
+
nornir_collection-0.0.12.dist-info/top_level.txt,sha256=OyCzPWABf-D0AOHm9ihrwdk5eq200BnKna6gIDspwsE,18
|
59
|
+
nornir_collection-0.0.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|