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,514 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ This module contains Cisco specific RESTCONF operation RPC tasks and functions for Nornir. Other custom
4
+ RESTCONF tasks for the /data url are not part of this helper file. Please take a look to nr_restconf.
5
+
6
+ The functions are ordered as followed:
7
+ - Helper Functions
8
+ - Single Nornir RESTCONF RPC Tasks
9
+ - Nornir RESTCONF RPC Tasks in regular Function
10
+ - Nornir RESTCONF RPC Tasks with CLI Fallback in regular Function
11
+ """
12
+
13
+ import json
14
+ import time
15
+ from typing import Union
16
+ import requests
17
+ from nornir.core import Nornir
18
+ from nornir.core.task import Task, Result
19
+ from nornir_collection.utils import print_result
20
+
21
+
22
+ #### Helper Functions ########################################################################################
23
+
24
+
25
+ def rc_cisco_operation_rpc( # pylint: disable=dangerous-default-value
26
+ task_obj: Task, rpc: str, payload: dict = {}
27
+ ) -> requests.Response:
28
+ """
29
+ TBD
30
+ """
31
+
32
+ # RESTCONF HTTP URL
33
+ host = task_obj.host.hostname
34
+ url = f"https://{host}:443/restconf/operations/{rpc}"
35
+
36
+ # RESTCONF HTTP header
37
+ headers = {"Accept": "application/yang-data+json", "Content-Type": "application/yang-data+json"}
38
+
39
+ # RESTCONF HTTP API call
40
+ response = requests.post(
41
+ url=url,
42
+ headers=headers,
43
+ data=json.dumps(payload),
44
+ auth=(task_obj.host.username, task_obj.host.password),
45
+ verify=False, # nosec
46
+ timeout=120,
47
+ )
48
+
49
+ return response
50
+
51
+
52
+ #### Single Nornir RESTCONF RPC Tasks ########################################################################
53
+
54
+
55
+ def rc_cisco_rpc_is_syncing_task(task: Task, verbose: bool = False) -> Result:
56
+ """
57
+ This Nornir task executes the Cisco specific operations RESTCONF RPC cisco-ia:is-syncing to check if the
58
+ configuration datastore is ready. If a sync is active the task backoff and try again until the datastore
59
+ is ready. The Nornir Result object is returned.
60
+ """
61
+ # Backoff sleep and attempt values
62
+ max_retry = 180 # How many times the range() loop will be done
63
+ sleep = 1 # Seconds to sleep between each range() loop attempt
64
+ waited = 0 # How many seconds hat to be waited until the datastore is ready
65
+
66
+ for _ in range(max_retry):
67
+ # RESTCONF HTTP API call
68
+ response = rc_cisco_operation_rpc(task_obj=task, rpc="cisco-ia:is-syncing")
69
+
70
+ # Set the verbose result string to add to the result summary
71
+ result_verbose = (
72
+ f"\n\nPayload: {json.dumps({}, indent=4)}\n"
73
+ + f"\nURL: {response.url}\n"
74
+ + f"Method: {response.request}\n"
75
+ + f"Response: {response}\n"
76
+ + f"Text: {response.text}"
77
+ )
78
+
79
+ if response.status_code == 200 and "No sync in progress" in response.text:
80
+ # No datastore sync -> Return the Nornir task result as successful
81
+ result = (
82
+ f"'{task.name}' -> RestconfResponse: <Success: True>\n"
83
+ + f"-> Datastore is ready after waiting {waited}s"
84
+ )
85
+ result = result + f"{result_verbose}" if verbose else result
86
+
87
+ # Return the Nornir task result
88
+ return Result(host=task.host, result=result, failed=False)
89
+
90
+ # Continue with next range() loop attempt
91
+ time.sleep(sleep)
92
+ waited = waited + sleep
93
+
94
+ # If the for loop is finish without success
95
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>"
96
+ # Set the message based on the response status code
97
+ result += (
98
+ f"\n-> Datastore is not ready after max waiting timeout of {waited}s"
99
+ if response.status_code == 200
100
+ else f"\n-> RESTCONF RPC API call failed with status code {response.status_code}"
101
+ )
102
+ result = result + result_verbose if verbose else result
103
+
104
+ # Return the Nornir task result as failed
105
+ return Result(host=task.host, result=result, failed=True)
106
+
107
+
108
+ def rc_cisco_rpc_save_config_task(task: Task, verbose: bool = False) -> Result:
109
+ """
110
+ TBD
111
+ """
112
+ # RESTCONF HTTP API call
113
+ response = rc_cisco_operation_rpc(task_obj=task, rpc="cisco-ia:save-config")
114
+
115
+ # Set the verbose result string to add to the result summary
116
+ result_verbose = (
117
+ f"\n\nPayload: {json.dumps({}, indent=4)}\n"
118
+ + f"\nURL: {response.url}\n"
119
+ + f"Method: {response.request}\n"
120
+ + f"Response: {response}\n"
121
+ + f"Text: {response.text}"
122
+ )
123
+
124
+ if response.status_code == 200:
125
+ result = f"'{task.name}' -> RestconfResponse: <Success: True>"
126
+ # Set the result print level
127
+ result = result + result_verbose if verbose else result
128
+
129
+ # Return the Nornir task result as successful
130
+ return Result(host=task.host, result=result)
131
+
132
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>" + result_verbose
133
+ # Return the Nornir task result as failed
134
+ return Result(host=task.host, result=result, failed=True)
135
+
136
+
137
+ def rc_cisco_rpc_copy_file_task(task: Task, source: str, destination: str, verbose: bool = False) -> Result:
138
+ """
139
+ TBD
140
+ """
141
+ # Payload
142
+ payload = {
143
+ "Cisco-IOS-XE-rpc:input": {
144
+ "source-drop-node-name": source,
145
+ "destination-drop-node-name": destination,
146
+ }
147
+ }
148
+ # RESTCONF HTTP API call
149
+ response = rc_cisco_operation_rpc(task_obj=task, rpc="Cisco-IOS-XE-rpc:copy", payload=payload)
150
+
151
+ # Set the verbose result string to add to the result summary
152
+ result_verbose = (
153
+ f"\n\nPayload: {json.dumps(payload, indent=4)}\n"
154
+ + f"\nURL: {response.url}\n"
155
+ + f"Method: {response.request}\n"
156
+ + f"Response: {response}\n"
157
+ + f"Text: {response.text}"
158
+ )
159
+
160
+ if response.status_code == 200:
161
+ result = (
162
+ f"'{task.name}' -> RestconfResponse: <Success: True>\n"
163
+ + f"-> Source: '{source}'\n"
164
+ + f"-> Destination: '{destination}'"
165
+ )
166
+ # Set the result print level
167
+ result = result + result_verbose if verbose else result
168
+
169
+ # Return the Nornir task result as successful
170
+ return Result(host=task.host, result=result, failed=False)
171
+
172
+ result = (
173
+ f"'{task.name}' -> RestconfResponse: <Success: False>\n"
174
+ + f"-> Source: '{source}'\n"
175
+ + f"-> Destination: '{destination}'"
176
+ + result_verbose
177
+ )
178
+ # Return the Nornir task result as failed
179
+ return Result(host=task.host, result=result, failed=True)
180
+
181
+
182
+ def rc_cisco_rpc_rollback_config_task(
183
+ task: Task, target_url: str, revert_timer: int = None, verbose: bool = False
184
+ ) -> Result:
185
+ """
186
+ TBD
187
+ """
188
+ # Base Payload
189
+ payload = {
190
+ "cisco-ia:input": {
191
+ "target-url": target_url,
192
+ "verbose": True,
193
+ }
194
+ }
195
+ # Optional add the revert-timer to the payload
196
+ if revert_timer:
197
+ payload["cisco-ia:input"]["revert-timer"] = revert_timer
198
+
199
+ # RESTCONF HTTP API call
200
+ response = rc_cisco_operation_rpc(task_obj=task, rpc="cisco-ia:rollback", payload=payload)
201
+
202
+ # Set the verbose result string to add to the result summary
203
+ result_verbose = (
204
+ f"\n\nPayload: {json.dumps(payload, indent=4)}\n"
205
+ + f"\nURL: {response.url}\n"
206
+ + f"Method: {response.request}\n"
207
+ + f"Response: {response}\n"
208
+ + f"Text: {response.text}"
209
+ )
210
+
211
+ # If the rollback was successful
212
+ if response.status_code == 200:
213
+ result = f"'{task.name}' -> RestconfResponse: <Success: True>\n" + f"-> Target-URL: '{target_url}'"
214
+ if revert_timer:
215
+ result = result + f"\n-> Revert-Timer: '{revert_timer}min'"
216
+ # Set the result print level
217
+ result = result + result_verbose if verbose else result
218
+
219
+ # Return the Nornir task result as successful
220
+ return Result(host=task.host, result=result, failed=False)
221
+
222
+ # Failed because the rollback file does not exist
223
+ if (response.status_code == 400) and (("cisco-ia:rollback" and "Could not open file") in response.text):
224
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>\n" + f"-> Target-URL: '{target_url}'"
225
+ if revert_timer:
226
+ result = result + f"\n-> Revert-Timer: '{revert_timer}'"
227
+ result = result + result_verbose
228
+ # Return the Nornir task result as successful
229
+ return Result(host=task.host, result=result, failed=True)
230
+
231
+ # Success but with some failed rollback commands -> Happen when commands change between software releases
232
+ if (response.status_code == 400) and (("cisco-ia:rollback" and "inconsistent value") in response.text):
233
+ result = f"'{task.name}' -> RestconfResponse: <Success: True>\n" + f"-> Target-URL: '{target_url}'"
234
+ if revert_timer:
235
+ result = result + f"\n-> Revert-Timer: '{revert_timer}'"
236
+ # Set the result print level
237
+ result = result + result_verbose if verbose else result
238
+ # Return the Nornir task result as successful
239
+ return Result(host=task.host, result=result, failed=False)
240
+
241
+ # Return the Nornir task result as failed
242
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>\n" + f"-> Target-URL: '{target_url}'"
243
+ if revert_timer:
244
+ result = result + f"\n-> Revert-Timer: '{revert_timer}'"
245
+ result = result + result_verbose
246
+ return Result(host=task.host, result=result, failed=True)
247
+
248
+
249
+ def rc_software_install_one_shot_task(task: Task, issu: bool = False, verbose: bool = False) -> Result:
250
+ """
251
+ This custom Nornir task loads the software destination file which have to be installed from the Nornir
252
+ inventory executes the Cisco specific operations RESTCONF RPC Cisco-IOS-XE-install-rpc:install to install
253
+ a software file in a one-shot approach which will install, commit and reload the switch. The Nornir
254
+ result object will be returned.
255
+ """
256
+
257
+ # Get the host destination file from the Nornir inventory
258
+ dest_file = task.host["software"]["dest_file"]
259
+
260
+ # Set the base payload for the RESTCONF API call
261
+ payload = {
262
+ "Cisco-IOS-XE-install-rpc:input": {
263
+ "uuid": f"Install {dest_file}",
264
+ "one-shot": True,
265
+ "path": f"flash:{dest_file}",
266
+ }
267
+ }
268
+ # Optional add issu to the payload
269
+ if issu:
270
+ payload["Cisco-IOS-XE-install-rpc:input"]["issu"] = True
271
+
272
+ # RESTCONF HTTP API call
273
+ response = rc_cisco_operation_rpc(
274
+ task_obj=task,
275
+ rpc="Cisco-IOS-XE-install-rpc:install",
276
+ payload=payload,
277
+ )
278
+
279
+ # Set the verbose result string to add to the result summary
280
+ result_verbose = (
281
+ f"\n\nPayload: {json.dumps(payload, indent=4)}\n"
282
+ + f"\nURL: {response.url}\n"
283
+ + f"Method: {response.request}\n"
284
+ + f"Response: {response}\n"
285
+ + f"Text: {response.text}"
286
+ )
287
+
288
+ if response.status_code == 204:
289
+ result = f"'{task.name}' -> RestconfResponse: <Success: True>"
290
+ # Set the result print level
291
+ result = result + result_verbose if verbose else result
292
+
293
+ # Return the Nornir task result as successful
294
+ return Result(host=task.host, result=result)
295
+
296
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>" + result_verbose
297
+ # Return the Nornir task result as failed
298
+ return Result(host=task.host, result=result, failed=True)
299
+
300
+
301
+ def rc_install_remove_inactive_task(task: Task, verbose: bool = False) -> Result:
302
+ """
303
+ This Nornir task executes the Cisco specific operations RESTCONF RPC Cisco-IOS-XE-install-rpc:remove to
304
+ remove all not needed software packages and files on the filesystem.
305
+ """
306
+ # Payload
307
+ payload = {
308
+ "Cisco-IOS-XE-install-rpc:input": {
309
+ "uuid": "Install Remove Inactive",
310
+ "inactive": True,
311
+ }
312
+ }
313
+
314
+ # RESTCONF HTTP API call
315
+ response = rc_cisco_operation_rpc(
316
+ task_obj=task,
317
+ rpc="Cisco-IOS-XE-install-rpc:remove",
318
+ payload=payload,
319
+ )
320
+
321
+ # Set the verbose result string to add to the result summary
322
+ result_verbose = (
323
+ f"\n\nPayload: {json.dumps(payload, indent=4)}\n"
324
+ + f"\nURL: {response.url}\n"
325
+ + f"Method: {response.request}\n"
326
+ + f"Response: {response}\n"
327
+ + f"Text: {response.text}"
328
+ )
329
+
330
+ if response.status_code == 204:
331
+ result = f"'{task.name}' -> RestconfResponse: <Success: True>"
332
+ # Set the result print level
333
+ result = result + result_verbose if verbose else result
334
+
335
+ # Return the Nornir task result as successful
336
+ return Result(host=task.host, result=result)
337
+
338
+ result = f"'{task.name}' -> RestconfResponse: <Success: False>" + result_verbose
339
+ # Return the Nornir task result as failed
340
+ return Result(host=task.host, result=result, failed=True)
341
+
342
+
343
+ #### Nornir RESTCONF RPC Tasks in regular Function ###########################################################
344
+
345
+
346
+ def rc_cisco_rpc_is_syncing(nr: Nornir, cfg_status: bool = True, verbose: bool = False) -> bool:
347
+ """
348
+ This function runs the custom Nornir task rc_cisco_rpc_is_syncing_task to verify the configuration
349
+ datastore sync state on a Cisco device with RESTCONF. Its a Cisco specific RPC that is sent to the device.
350
+ The result will be printed to std-out in custom Nornir style.
351
+ """
352
+ # pylint: disable=invalid-name
353
+
354
+ # Return False if cfg_status argument is False
355
+ if not cfg_status:
356
+ return False
357
+
358
+ # Run the Nornir Task rc_cisco_rpc_is_syncing_task
359
+ task_result = nr.run(
360
+ task=rc_cisco_rpc_is_syncing_task,
361
+ name="RESTCONF verify is-syncing",
362
+ verbose=verbose,
363
+ on_failed=True,
364
+ )
365
+
366
+ # Print the Nornir task result
367
+ print_result(task_result)
368
+
369
+ # Return False if the task failed or True if the task was successful
370
+ return not bool(task_result.failed)
371
+
372
+
373
+ def rc_cisco_rpc_save_config(nr: Nornir, cfg_status: bool = True, verbose: bool = False) -> bool:
374
+ """
375
+ This function runs the custom Nornir task rc_cisco_rpc_save_config_task to save the configuration on a
376
+ Cisco device with RESTCONF. Its a Cisco specific RPC that is sent to the device. The result will be
377
+ printed to std-out in Nornir style and the function return True or False depending wheather the task was
378
+ successful.
379
+ """
380
+ # pylint: disable=invalid-name
381
+
382
+ # Return False if cfg_status argument is False
383
+ if not cfg_status:
384
+ return False
385
+
386
+ # Run the custom Nornir task rc_cisco_rpc_save_config_task
387
+ task_result = nr.run(
388
+ task=rc_cisco_rpc_save_config_task,
389
+ name="RESTCONF save config",
390
+ verbose=verbose,
391
+ on_failed=True,
392
+ )
393
+
394
+ # Print the Nornir task result
395
+ print_result(task_result)
396
+
397
+ # Return False if the task failed or True if the task was successful
398
+ return not bool(task_result.failed)
399
+
400
+
401
+ def rc_cisco_rpc_copy_file(
402
+ nr: Nornir, source: str, destination: str, name: Union[str, None] = None, verbose=False
403
+ ) -> bool:
404
+ """
405
+ This function runs the custom Nornir task rc_cisco_rpc_copy_file_task to copy a file from or to a Cisco
406
+ device with RESTCONF. Its a Cisco specific RPC that is sent to the device. The result will be printed to
407
+ std-out in Nornir style and the function return True or False depending wheather the task was successful.
408
+ """
409
+ # pylint: disable=invalid-name
410
+
411
+ # Set a custom task name if the argument name is not None
412
+ name = name if name else "RESTCONF copy file"
413
+
414
+ # Run the custom Nornir task rc_cisco_rpc_copy_file_task
415
+ task_result = nr.run(
416
+ task=rc_cisco_rpc_copy_file_task,
417
+ name=name,
418
+ source=source,
419
+ destination=destination,
420
+ verbose=verbose,
421
+ on_failed=True,
422
+ )
423
+
424
+ # Print the Nornir task result
425
+ print_result(task_result)
426
+
427
+ # Return False if the task failed or True if the task was successful
428
+ return not bool(task_result.failed)
429
+
430
+
431
+ def rc_cisco_rpc_rollback_config(
432
+ nr: Nornir,
433
+ target_url: str,
434
+ revert_timer: int = None,
435
+ name: Union[str, None] = None,
436
+ verbose: bool = False,
437
+ ) -> bool:
438
+ """
439
+ This function runs the custom Nornir task rc_cisco_rpc_rollback_config_task to rollback the copy of a
440
+ Cisco device to a config specified by a target-url with RESTCONF. Its a Cisco specific RPC that is sent to
441
+ the device. The result will be printed to std-out in custom Nornir style and the function return True or
442
+ False depending wheather the task was successful.
443
+ """
444
+ # pylint: disable=invalid-name
445
+
446
+ # Set a custom task name if the argument name is not None
447
+ name = name if name else "RESTCONF rollback config"
448
+
449
+ # Run the custom Nornir task rc_cisco_rpc_rollback_config_task
450
+ task_result = nr.run(
451
+ task=rc_cisco_rpc_rollback_config_task,
452
+ name=name,
453
+ target_url=target_url,
454
+ revert_timer=revert_timer,
455
+ verbose=verbose,
456
+ on_failed=True,
457
+ )
458
+
459
+ # Print the Nornir task result
460
+ print_result(task_result)
461
+
462
+ # Return False if the task failed or True if the task was successful
463
+ return not bool(task_result.failed)
464
+
465
+
466
+ def rc_software_install_one_shot(nr: Nornir, issu: bool = False, verbose: bool = False) -> bool:
467
+ """
468
+ This function takes the result of the function host_dict as an argument andruns the custom
469
+ Nornir task rc_software_install_one_shot_task to start the one-shot installation process of the desired
470
+ software version. The result will be printed to std-out in custom Nornir style and the script terminates
471
+ with an info message in case of an error.
472
+ """
473
+ # pylint: disable=invalid-name
474
+
475
+ # Run the custom Nornir task rc_software_install_one_shot_task
476
+ task_result = nr.run(
477
+ task=rc_software_install_one_shot_task,
478
+ name="RESTCONF one-shot install",
479
+ issu=issu,
480
+ verbose=verbose,
481
+ on_failed=True,
482
+ )
483
+
484
+ # Print the Nornir task result
485
+ print_result(task_result)
486
+
487
+ # Return False if the task failed or True if the task was successful
488
+ return not bool(task_result.failed)
489
+
490
+
491
+ def rc_install_remove_inactive(nr: Nornir, verbose: bool = False) -> bool:
492
+ """
493
+ This function runs the Nornir task rc_install_remove_inactive_task to to remove all not needed software
494
+ packages and files on the filesystem with RESTCONF. The result will be printed to std-out in custom Nornir
495
+ style and the script terminates with an info message in case of an error.
496
+ """
497
+ # pylint: disable=invalid-name
498
+
499
+ # Run the custom Nornir task rc_install_remove_inactive_task
500
+ task_result = nr.run(
501
+ task=rc_install_remove_inactive_task,
502
+ name="RESTCONF install remove inactive",
503
+ verbose=verbose,
504
+ on_failed=True,
505
+ )
506
+
507
+ # Print the Nornir task result
508
+ print_result(task_result)
509
+
510
+ # Return False if the task failed or True if the task was successful
511
+ return not bool(task_result.failed)
512
+
513
+
514
+ #### Nornir RESTCONF RPC Tasks with CLI Fallback in regular Function #########################################
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ This module contains complete RESTCONF configuration workflows from multiple dsc_nornir functions.
4
+
5
+ The functions are ordered as followed:
6
+ - Complete RESTCONF configuration workflows
7
+ """
8
+
9
+ from nornir.core import Nornir
10
+ from nornir_collection.utils import print_task_title, exit_error
11
+ from nornir_collection.cisco.configuration_management.restconf.cisco_rpc import (
12
+ rc_cisco_rpc_is_syncing,
13
+ rc_cisco_rpc_rollback_config,
14
+ rc_cisco_rpc_copy_file,
15
+ )
16
+
17
+
18
+ #### Complete RESTCONF Configuration Workflow 01 #############################################################
19
+
20
+
21
+ def rc_replace_config(
22
+ nr: Nornir,
23
+ rebuild: bool = False,
24
+ cfg_status: bool = True,
25
+ revert_timer: int = None,
26
+ verbose: bool = False,
27
+ ) -> bool:
28
+ """
29
+ Replace the current configuration with a specified configuration file.
30
+ This function replaces the current configuration with the golden-config by default or the day0-config
31
+ if the rebuild argument is set to True. It returns True if the operation was successful, otherwise False.
32
+ """
33
+ # pylint: disable=invalid-name
34
+
35
+ # Return False if cfg_status argument is False
36
+ if not cfg_status:
37
+ return False
38
+
39
+ # Set rollback_config to day0-config if rebuild is True, else set it to golden-config
40
+ rollback_config = "day0-config" if rebuild else "golden-config"
41
+
42
+ # Print the task title if revert_timer is not set
43
+ if not revert_timer:
44
+ print_task_title(f"Replace current config with {rollback_config}")
45
+
46
+ # Checks if an active datastore sync in ongoing and wait until is finish
47
+ rc_cisco_rpc_is_syncing(nr=nr, verbose=verbose)
48
+
49
+ # Replace the running-config with the rollback_config from the switch flash:
50
+ cfg_status = rc_cisco_rpc_rollback_config(
51
+ nr=nr,
52
+ name=f"RESTCONF rollback {rollback_config}",
53
+ target_url=f"flash:{rollback_config}",
54
+ revert_timer=revert_timer,
55
+ verbose=verbose,
56
+ )
57
+
58
+ return cfg_status
59
+
60
+
61
+ def rc_update_golden_config(nr: Nornir, verbose: bool = False) -> None:
62
+ """
63
+ Updates the golden configuration on Cisco devices using RESTCONF.
64
+ This function performs the following steps:
65
+ 1. Prints the task title for updating the golden configuration.
66
+ 2. Checks if an active datastore synchronization is ongoing and waits until it finishes.
67
+ 3. Saves the current running configuration as the new golden configuration to the local device flash.
68
+ 4. Exits the script if the configuration update fails.
69
+ """
70
+ # pylint: disable=invalid-name
71
+
72
+ # Update golden config
73
+ task_text = "RESTCONF update golden-config"
74
+ print_task_title(title=task_text)
75
+
76
+ # Checks if an active datastore sync in ongoing and wait until is finish
77
+ rc_cisco_rpc_is_syncing(nr=nr, verbose=verbose)
78
+
79
+ # Save the new config as the new golden config to the local device flash
80
+ cfg_status = rc_cisco_rpc_copy_file(
81
+ nr=nr,
82
+ name=task_text,
83
+ source="running-config",
84
+ destination="flash:golden-config",
85
+ verbose=verbose,
86
+ )
87
+
88
+ # Exit the script if the config status if False
89
+ if not cfg_status:
90
+ text = "ALERT: UPDATE GOLDEN-CONFIG HAVE FAILED!"
91
+ msg = [
92
+ "-> RESTCONF failed to update the golden configuration",
93
+ "-> The remaining tasks have been omitted due to RESTCONF failed",
94
+ ]
95
+ exit_error(task_text=task_text, text=text, msg=msg)