nornir-collection 0.0.1__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.
Files changed (59) hide show
  1. nornir_collection/__init__.py +0 -0
  2. nornir_collection/batfish/__init__.py +0 -0
  3. nornir_collection/batfish/assert_config.py +358 -0
  4. nornir_collection/batfish/utils.py +129 -0
  5. nornir_collection/cisco/__init__.py +0 -0
  6. nornir_collection/cisco/configuration_management/__init__.py +0 -0
  7. nornir_collection/cisco/configuration_management/cli/__init__.py +0 -0
  8. nornir_collection/cisco/configuration_management/cli/config_tasks.py +569 -0
  9. nornir_collection/cisco/configuration_management/cli/config_workflow.py +107 -0
  10. nornir_collection/cisco/configuration_management/cli/show_tasks.py +677 -0
  11. nornir_collection/cisco/configuration_management/netconf/__init__.py +0 -0
  12. nornir_collection/cisco/configuration_management/netconf/config_tasks.py +564 -0
  13. nornir_collection/cisco/configuration_management/netconf/config_workflow.py +298 -0
  14. nornir_collection/cisco/configuration_management/netconf/nr_cfg_iosxe_netconf.py +186 -0
  15. nornir_collection/cisco/configuration_management/netconf/ops_tasks.py +307 -0
  16. nornir_collection/cisco/configuration_management/processor.py +151 -0
  17. nornir_collection/cisco/configuration_management/pyats.py +236 -0
  18. nornir_collection/cisco/configuration_management/restconf/__init__.py +0 -0
  19. nornir_collection/cisco/configuration_management/restconf/cisco_rpc.py +514 -0
  20. nornir_collection/cisco/configuration_management/restconf/config_workflow.py +95 -0
  21. nornir_collection/cisco/configuration_management/restconf/tasks.py +325 -0
  22. nornir_collection/cisco/configuration_management/utils.py +511 -0
  23. nornir_collection/cisco/software_upgrade/__init__.py +0 -0
  24. nornir_collection/cisco/software_upgrade/cisco_software_upgrade.py +283 -0
  25. nornir_collection/cisco/software_upgrade/utils.py +794 -0
  26. nornir_collection/cisco/support_api/__init__.py +0 -0
  27. nornir_collection/cisco/support_api/api_calls.py +1173 -0
  28. nornir_collection/cisco/support_api/cisco_maintenance_report.py +221 -0
  29. nornir_collection/cisco/support_api/cisco_support.py +727 -0
  30. nornir_collection/cisco/support_api/reports.py +747 -0
  31. nornir_collection/cisco/support_api/utils.py +316 -0
  32. nornir_collection/fortinet/__init__.py +0 -0
  33. nornir_collection/fortinet/utils.py +36 -0
  34. nornir_collection/git.py +224 -0
  35. nornir_collection/netbox/__init__.py +0 -0
  36. nornir_collection/netbox/custom_script.py +107 -0
  37. nornir_collection/netbox/inventory.py +360 -0
  38. nornir_collection/netbox/scan_prefixes_and_update_ip_addresses.py +989 -0
  39. nornir_collection/netbox/set_device_status.py +67 -0
  40. nornir_collection/netbox/sync_datasource.py +111 -0
  41. nornir_collection/netbox/update_cisco_inventory_data.py +158 -0
  42. nornir_collection/netbox/update_cisco_support_plugin_data.py +339 -0
  43. nornir_collection/netbox/update_fortinet_inventory_data.py +161 -0
  44. nornir_collection/netbox/update_purestorage_inventory_data.py +144 -0
  45. nornir_collection/netbox/utils.py +261 -0
  46. nornir_collection/netbox/verify_device_primary_ip.py +202 -0
  47. nornir_collection/nornir_plugins/__init__.py +0 -0
  48. nornir_collection/nornir_plugins/inventory/__init__.py +0 -0
  49. nornir_collection/nornir_plugins/inventory/netbox.py +250 -0
  50. nornir_collection/nornir_plugins/inventory/staggered_yaml.py +143 -0
  51. nornir_collection/nornir_plugins/inventory/utils.py +277 -0
  52. nornir_collection/purestorage/__init__.py +0 -0
  53. nornir_collection/purestorage/utils.py +53 -0
  54. nornir_collection/utils.py +741 -0
  55. nornir_collection-0.0.1.dist-info/LICENSE +21 -0
  56. nornir_collection-0.0.1.dist-info/METADATA +136 -0
  57. nornir_collection-0.0.1.dist-info/RECORD +59 -0
  58. nornir_collection-0.0.1.dist-info/WHEEL +5 -0
  59. nornir_collection-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,325 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ This module contains RESTCONF functions and tasks related to Nornir.
4
+
5
+ The functions are ordered as followed:
6
+ - Single Nornir RESTCONF tasks
7
+ - Nornir RESTCONF tasks in regular function
8
+ """
9
+
10
+ import json
11
+ import traceback
12
+ import requests
13
+ from nornir.core import Nornir
14
+ from nornir.core.task import Task, Result
15
+ from nornir_collection.cisco.configuration_management.restconf.cisco_rpc import (
16
+ rc_software_install_one_shot_task,
17
+ rc_install_remove_inactive_task,
18
+ )
19
+ from nornir_collection.cisco.configuration_management.cli.show_tasks import (
20
+ cli_verify_current_software_version_task,
21
+ cli_install_one_shot_task,
22
+ cli_install_remove_inactive_task,
23
+ )
24
+ from nornir_collection.utils import (
25
+ print_result,
26
+ exit_error,
27
+ nr_filter_inventory_from_host_list,
28
+ )
29
+
30
+
31
+ #### Helper Functions #######################################################################################
32
+
33
+
34
+ def rc_cisco_get(url: str, auth: tuple, verify: bool = False, timeout: int = 120) -> dict:
35
+ """
36
+ TBD
37
+ """
38
+ # RESTCONF HTTP header
39
+ headers = {"Accept": "application/yang-data+json", "Content-Type": "application/yang-data+json"}
40
+
41
+ # RESTCONF HTTP API call
42
+ response = requests.get(url=url, headers=headers, auth=auth, verify=verify, timeout=timeout) # nosec
43
+
44
+ # Result dict to return as task result
45
+ result = {
46
+ "url": url,
47
+ "response": response,
48
+ "method": response.request,
49
+ "status_code": response.status_code,
50
+ "elapsed": response.elapsed.total_seconds(),
51
+ "text": response.text,
52
+ "json": response.json(),
53
+ }
54
+
55
+ # Return the result dictionary
56
+ return result
57
+
58
+
59
+ #### Single Nornir RESTCONF Tasks ###########################################################################
60
+
61
+
62
+ def rc_cisco_get_task(task: Task, yang_data_query: str) -> Result:
63
+ """
64
+ This custom Nornir task executes a RESTCONF GET request to a yang data query and returns a dictionary with
65
+ the whole RESTCONF response as well as some custom formated data for further processing.
66
+ """
67
+ # RESTCONF HTTP URL
68
+ restconf_path = f"restconf/data/{yang_data_query}"
69
+ url = f"https://{task.host.hostname}:443/{restconf_path}"
70
+
71
+ # RESTCONF HTTP header
72
+ headers = {
73
+ "Accept": "application/yang-data+json",
74
+ "Content-Type": "application/yang-data+json",
75
+ }
76
+
77
+ # RESTCONF HTTP API call
78
+ rc_response = requests.get( # nosec
79
+ url=url, headers=headers, auth=(task.host.username, task.host.password), verify=False, timeout=120
80
+ )
81
+
82
+ # Result dict to return as task result
83
+ result = {
84
+ "url": url,
85
+ "response": rc_response,
86
+ "method": rc_response.request,
87
+ "status_code": rc_response.status_code,
88
+ "elapsed": rc_response.elapsed.total_seconds(),
89
+ "json": rc_response.json(),
90
+ }
91
+
92
+ return Result(host=task.host, result=result)
93
+
94
+
95
+ def rc_verify_current_software_version_task(task: Task, verbose=False) -> Result:
96
+ """
97
+ TBD
98
+ """
99
+ # Get the desired version from the Nornir inventory
100
+ desired_version = task.host["software"]["version"]
101
+
102
+ # RESTCONF HTTP URL
103
+ rc_path = "restconf/data/Cisco-IOS-XE-install-oper:install-oper-data/install-location-information"
104
+ url = f"https://{task.host.hostname}:443/{rc_path}"
105
+ # RESTCONF HTTP header
106
+ headers = {
107
+ "Accept": "application/yang-data+json",
108
+ "Content-Type": "application/yang-data+json",
109
+ }
110
+
111
+ try:
112
+ # RESTCONF HTTP API call
113
+ response = requests.get( # nosec
114
+ url=url, headers=headers, auth=(task.host.username, task.host.password), verify=False, timeout=120
115
+ )
116
+ # Get the current version from the task result
117
+ current_version = response.json()["Cisco-IOS-XE-install-oper:install-location-information"][0][
118
+ "install-version-state-info"
119
+ ][0]["version"]
120
+ except: # pylint: disable=bare-except
121
+ # Define the result as iosxe_c9200 is not implemented yet
122
+ custom_result = f"'{task.name}' -> NornirResponse: <Success: False>\n" f"\n{traceback.format_exc()}"
123
+ # Return the custom Nornir result as success
124
+ return Result(host=task.host, custom_result=custom_result, failed=True, use_fallback=True)
125
+
126
+ # Slice the variable to have only the fist 8 characters of the version number which should match to
127
+ # the Cisco version naming convention of xx.xx.xx
128
+ current_version = current_version[:8]
129
+ # Replace all 0 in the xe_version to normalizing iosxe and non-iosxe version format
130
+ # -> Make 17.03.05 to 17.3.5
131
+ current_version = current_version.replace("0", "")
132
+ # Write the current version into the Nornir inventory
133
+ task.host["software"]["current_version"] = current_version
134
+ # Prepare needed variables for further processing
135
+ elapsed = response.elapsed.total_seconds()
136
+
137
+ # Define the verbose result
138
+ verbose_result = (
139
+ f"URL: {url}\n"
140
+ f"Method: {response.request}\n"
141
+ f"Response: {response}\n"
142
+ f"Current version from JSON payload: {json.dumps(current_version, sort_keys=True, indent=4)}"
143
+ )
144
+
145
+ # If the RESTCONF call was successful
146
+ if response.status_code == 200:
147
+ # If the desired version and the current version are the same
148
+ if desired_version in current_version:
149
+ # Define the summary result
150
+ result_summary = (
151
+ f"'{task.name}' -> RestconfResponse {response} in {elapsed}s\n"
152
+ f"-> Desired version {desired_version} match installed version {current_version}"
153
+ )
154
+ # Define the custom_result variable for print_result
155
+ custom_result = result_summary + "\n\n" + verbose_result if verbose else result_summary
156
+
157
+ # Return the custom Nornir result as success
158
+ return Result(host=task.host, custom_result=custom_result)
159
+
160
+ # Else the desired version and the current version are not the same
161
+ # Define the summary result
162
+ result_summary = (
163
+ f"'{task.name}' -> RestconfResponse {response} in {elapsed}s\n"
164
+ f"-> Desired version {desired_version} don't match installed version {current_version}"
165
+ )
166
+ # Define the custom_result variable for print_result
167
+ custom_result = result_summary + "\n\n" + verbose_result if verbose else result_summary
168
+
169
+ # Return the custom Nornir result as failed
170
+ return Result(host=task.host, custom_result=custom_result, failed=True, need_upgrade=True)
171
+
172
+ # Define the custom_result variable for print_result
173
+ custom_result = f"'{task.name}' -> RestconfResponse {response} in {elapsed}s\n\n{verbose_result}"
174
+
175
+ # If the RESTCONF call was not successful -> The task failed and set the use_fallback to True
176
+ return Result(host=task.host, custom_result=custom_result, failed=True, use_fallback=True)
177
+
178
+
179
+ #### Nornir RESTCONF tasks in regular Function ##############################################################
180
+
181
+
182
+ def rc_verify_current_software_version_fallback_cli(nr: Nornir, verbose=False) -> list:
183
+ """
184
+ TBD
185
+ """
186
+ # pylint: disable=invalid-name
187
+
188
+ # Get software version with RESTCONF
189
+ rc_task_result = nr.run(
190
+ task=rc_verify_current_software_version_task,
191
+ name="RESTCONF verify current software version",
192
+ verbose=verbose,
193
+ on_failed=True,
194
+ )
195
+
196
+ # Print the Nornir rc_verify_current_software_version_task task result
197
+ print_result(rc_task_result, attrs="custom_result")
198
+
199
+ # Create a list with all host that failed the RESTCONF task and need to use the CLI fallback task
200
+ rc_fallback_hosts = [host for host in rc_task_result if hasattr(rc_task_result[host], "use_fallback")]
201
+
202
+ # If the rc_fallback_hosts list is empty, the CLI fallback is not needed and the failed_hosts list can
203
+ # be returned. The failed host list contains now only host with not matching software version
204
+ if not rc_fallback_hosts:
205
+ failed_hosts = list(rc_task_result.failed_hosts)
206
+ return failed_hosts
207
+
208
+ # Re-filter the Nornir inventory on the failed_hosts only
209
+ nr_obj_fallback = nr_filter_inventory_from_host_list(
210
+ nr=nr,
211
+ filter_reason="CLI fallback for hosts that failed the RESTCONF task:",
212
+ host_list=rc_fallback_hosts,
213
+ )
214
+
215
+ # Get software version with CLI
216
+ cli_task_result = nr_obj_fallback.run(
217
+ task=cli_verify_current_software_version_task,
218
+ name="CLI verify current software version",
219
+ verbose=verbose,
220
+ on_failed=True,
221
+ )
222
+
223
+ # Print the Nornir cli_verify_current_software_version_task task result
224
+ print_result(cli_task_result)
225
+
226
+ # If the overall task result failed -> Print results and exit the script
227
+ for host in cli_task_result:
228
+ if hasattr(cli_task_result[host], "overall_task_failed"):
229
+ exit_error(task_text="RESTCONF and CLI verify current software version")
230
+
231
+ # Create a list with all host which the RESTCONF task was successful but they need a software upgrade
232
+ rc_upgrade_hosts = [host for host in rc_task_result if hasattr(rc_task_result[host], "need_upgrade")]
233
+ # Create a list with all host which the CLI task was successful but they need a software upgrade
234
+ cli_upgrade_hosts = [host for host in cli_task_result if hasattr(cli_task_result[host], "need_upgrade")]
235
+
236
+ # List to fill with all hosts not matching the desired software version
237
+ failed_hosts = rc_upgrade_hosts + cli_upgrade_hosts
238
+
239
+ return failed_hosts
240
+
241
+
242
+ def rc_software_install_one_shot_fallback_cli(nr: Nornir, issu: bool = False, verbose: bool = False) -> bool:
243
+ """
244
+ TBD
245
+ """
246
+ # pylint: disable=invalid-name
247
+
248
+ # Run the custom Nornir task rc_software_install_one_shot_task
249
+ rc_task_result = nr.run(
250
+ task=rc_software_install_one_shot_task,
251
+ name="RESTCONF one-shot install",
252
+ issu=issu,
253
+ verbose=verbose,
254
+ on_failed=True,
255
+ )
256
+
257
+ # Print the Nornir rc_software_install_one_shot_task task result
258
+ print_result(rc_task_result)
259
+
260
+ # If the failed_hosts list is empty, the CLI fallback is not needed and True can be returned.
261
+ if not list(rc_task_result.failed_hosts):
262
+ return True
263
+
264
+ # Re-filter the Nornir inventory on the failed_hosts of rc_task_result only
265
+ nr_obj_fallback = nr_filter_inventory_from_host_list(
266
+ nr=nr,
267
+ filter_reason="CLI fallback for hosts that failed the RESTCONF task:",
268
+ host_list=list(rc_task_result.failed_hosts),
269
+ )
270
+
271
+ # Run the custom Nornir task cli_install_one_shot_task
272
+ cli_task_result = nr_obj_fallback.run(
273
+ task=cli_install_one_shot_task,
274
+ name="CLI one-shot install",
275
+ issu=issu,
276
+ verbose=verbose,
277
+ on_failed=True,
278
+ )
279
+
280
+ # Print the Nornir cli_install_one_shot_task task result
281
+ print_result(cli_task_result)
282
+
283
+ # Return False if the task failed or True if the task was successful
284
+ return not bool(cli_task_result.failed)
285
+
286
+
287
+ def rc_install_remove_inactive_fallback_cli(nr: Nornir, verbose: bool = False) -> bool:
288
+ """
289
+ TBD
290
+ """
291
+ # pylint: disable=invalid-name
292
+
293
+ # Run the custom Nornir task rc_install_remove_inactive_task
294
+ rc_task_result = nr.run(
295
+ task=rc_install_remove_inactive_task,
296
+ name="RESTCONF install remove inactive",
297
+ verbose=verbose,
298
+ on_failed=True,
299
+ )
300
+ # Print the Nornir rc_install_remove_inactive_task task result
301
+ print_result(rc_task_result)
302
+
303
+ # If the failed_hosts list is empty, the CLI fallback is not needed and True can be returned.
304
+ if not list(rc_task_result.failed_hosts):
305
+ return True
306
+
307
+ # Re-filter the Nornir inventory on the failed_hosts of rc_task_result only
308
+ nr_obj_fallback = nr_filter_inventory_from_host_list(
309
+ nr=nr,
310
+ filter_reason="CLI fallback for hosts that failed the RESTCONF task:",
311
+ host_list=list(rc_task_result.failed_hosts),
312
+ )
313
+
314
+ # Run the custom Nornir task cli_install_remove_inactive_task
315
+ cli_task_result = nr_obj_fallback.run(
316
+ task=cli_install_remove_inactive_task,
317
+ name="CLI install remove inactive",
318
+ verbose=verbose,
319
+ on_failed=True,
320
+ )
321
+ # Print the Nornir cli_install_remove_inactive_task task result
322
+ print_result(cli_task_result)
323
+
324
+ # Return False if the task failed or True if the task was successful
325
+ return not bool(cli_task_result.failed)