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.
- nornir_collection/__init__.py +0 -0
- nornir_collection/batfish/__init__.py +0 -0
- nornir_collection/batfish/assert_config.py +358 -0
- nornir_collection/batfish/utils.py +129 -0
- nornir_collection/cisco/__init__.py +0 -0
- nornir_collection/cisco/configuration_management/__init__.py +0 -0
- nornir_collection/cisco/configuration_management/cli/__init__.py +0 -0
- nornir_collection/cisco/configuration_management/cli/config_tasks.py +569 -0
- nornir_collection/cisco/configuration_management/cli/config_workflow.py +107 -0
- nornir_collection/cisco/configuration_management/cli/show_tasks.py +677 -0
- nornir_collection/cisco/configuration_management/netconf/__init__.py +0 -0
- nornir_collection/cisco/configuration_management/netconf/config_tasks.py +564 -0
- nornir_collection/cisco/configuration_management/netconf/config_workflow.py +298 -0
- nornir_collection/cisco/configuration_management/netconf/nr_cfg_iosxe_netconf.py +186 -0
- nornir_collection/cisco/configuration_management/netconf/ops_tasks.py +307 -0
- nornir_collection/cisco/configuration_management/processor.py +151 -0
- nornir_collection/cisco/configuration_management/pyats.py +236 -0
- nornir_collection/cisco/configuration_management/restconf/__init__.py +0 -0
- nornir_collection/cisco/configuration_management/restconf/cisco_rpc.py +514 -0
- nornir_collection/cisco/configuration_management/restconf/config_workflow.py +95 -0
- nornir_collection/cisco/configuration_management/restconf/tasks.py +325 -0
- nornir_collection/cisco/configuration_management/utils.py +511 -0
- nornir_collection/cisco/software_upgrade/__init__.py +0 -0
- nornir_collection/cisco/software_upgrade/cisco_software_upgrade.py +283 -0
- nornir_collection/cisco/software_upgrade/utils.py +794 -0
- nornir_collection/cisco/support_api/__init__.py +0 -0
- nornir_collection/cisco/support_api/api_calls.py +1173 -0
- nornir_collection/cisco/support_api/cisco_maintenance_report.py +221 -0
- nornir_collection/cisco/support_api/cisco_support.py +727 -0
- nornir_collection/cisco/support_api/reports.py +747 -0
- nornir_collection/cisco/support_api/utils.py +316 -0
- nornir_collection/fortinet/__init__.py +0 -0
- nornir_collection/fortinet/utils.py +36 -0
- nornir_collection/git.py +224 -0
- nornir_collection/netbox/__init__.py +0 -0
- nornir_collection/netbox/custom_script.py +107 -0
- nornir_collection/netbox/inventory.py +360 -0
- nornir_collection/netbox/scan_prefixes_and_update_ip_addresses.py +989 -0
- nornir_collection/netbox/set_device_status.py +67 -0
- nornir_collection/netbox/sync_datasource.py +111 -0
- nornir_collection/netbox/update_cisco_inventory_data.py +158 -0
- nornir_collection/netbox/update_cisco_support_plugin_data.py +339 -0
- nornir_collection/netbox/update_fortinet_inventory_data.py +161 -0
- nornir_collection/netbox/update_purestorage_inventory_data.py +144 -0
- nornir_collection/netbox/utils.py +261 -0
- nornir_collection/netbox/verify_device_primary_ip.py +202 -0
- nornir_collection/nornir_plugins/__init__.py +0 -0
- nornir_collection/nornir_plugins/inventory/__init__.py +0 -0
- nornir_collection/nornir_plugins/inventory/netbox.py +250 -0
- nornir_collection/nornir_plugins/inventory/staggered_yaml.py +143 -0
- nornir_collection/nornir_plugins/inventory/utils.py +277 -0
- nornir_collection/purestorage/__init__.py +0 -0
- nornir_collection/purestorage/utils.py +53 -0
- nornir_collection/utils.py +741 -0
- nornir_collection-0.0.1.dist-info/LICENSE +21 -0
- nornir_collection-0.0.1.dist-info/METADATA +136 -0
- nornir_collection-0.0.1.dist-info/RECORD +59 -0
- nornir_collection-0.0.1.dist-info/WHEEL +5 -0
- nornir_collection-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,298 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
This module contains complete NETCONF config workflows from multiple dsc_nornir functions.
|
4
|
+
|
5
|
+
The functions are ordered as followed:
|
6
|
+
- Complete NETCONF config workflows
|
7
|
+
"""
|
8
|
+
|
9
|
+
|
10
|
+
import time
|
11
|
+
from nornir.core import Nornir, Task
|
12
|
+
from nornir_collection.utils import (
|
13
|
+
print_task_title,
|
14
|
+
task_name,
|
15
|
+
task_result,
|
16
|
+
exit_info,
|
17
|
+
task_error,
|
18
|
+
exit_error,
|
19
|
+
)
|
20
|
+
from nornir_collection.cisco.configuration_management.restconf.config_workflow import rc_replace_config
|
21
|
+
from nornir_collection.cisco.configuration_management.netconf.config_tasks import (
|
22
|
+
nc_cfg_cleanup,
|
23
|
+
nc_cfg_tpl,
|
24
|
+
nc_cfg_tpl_int,
|
25
|
+
)
|
26
|
+
from nornir_collection.cisco.configuration_management.netconf.ops_tasks import (
|
27
|
+
# nc_lock,
|
28
|
+
# nc_unlock,
|
29
|
+
nc_validate,
|
30
|
+
nc_discard,
|
31
|
+
nc_commit,
|
32
|
+
)
|
33
|
+
from nornir_collection.cisco.configuration_management.restconf.cisco_rpc import (
|
34
|
+
rc_cisco_rpc_is_syncing,
|
35
|
+
rc_cisco_rpc_save_config,
|
36
|
+
)
|
37
|
+
from nornir_collection.cisco.configuration_management.processor import nr_testsprocessor
|
38
|
+
from nornir_collection.cisco.configuration_management.cli.config_tasks import cli_confirm_or_revert_config
|
39
|
+
|
40
|
+
|
41
|
+
#### NETCONF config Workflow Helper #########################################################################
|
42
|
+
|
43
|
+
|
44
|
+
def _nc_exit_dry_run(nr: Task, cfg_status: bool, verbose: bool) -> None:
|
45
|
+
"""
|
46
|
+
Handles the exit process for a NETCONF dry-run operation.
|
47
|
+
This function performs the following steps:
|
48
|
+
1. Discards all changes on the NETCONF candidate datastore.
|
49
|
+
2. Unlocks the NETCONF datastore.
|
50
|
+
3. Verifies the NETCONF dry-run status of the config results.
|
51
|
+
4. Exits the script with an appropriate message based on the config status.
|
52
|
+
|
53
|
+
!!! NETCONF lock/unlock rpc have been commented out as the unlock fails since 17.12.X !!!
|
54
|
+
"""
|
55
|
+
# pylint: disable=invalid-name
|
56
|
+
|
57
|
+
# Discard all changes on the NETCONF candidate datastore
|
58
|
+
nc_discard(nr=nr, verbose=verbose)
|
59
|
+
|
60
|
+
# Unlock the NETCONF datastore
|
61
|
+
# nc_unlock(nr=nr, verbose=verbose)
|
62
|
+
|
63
|
+
# Verify NETCONF dry-run status of the config results and exit the script with a proper message
|
64
|
+
task_text = "Verify NETCONF dry-run config results"
|
65
|
+
msg = "-> The remaining tasks have been omitted due to the NETCONF dry-run execution"
|
66
|
+
print_task_title(title=task_text)
|
67
|
+
print(task_name(text=task_text))
|
68
|
+
|
69
|
+
if cfg_status:
|
70
|
+
text = "GOOD NEWS! ALL CONFIGS HAVE BEEN RENDERED AND VALIDATED SUCCESSFUL!"
|
71
|
+
exit_info(task_text=task_text, text=text, msg=msg)
|
72
|
+
else:
|
73
|
+
text = "ALERT: ONE OR MORE CONFIGS HAVE FAILED!"
|
74
|
+
exit_error(task_text=task_text, text=text, msg=msg)
|
75
|
+
|
76
|
+
|
77
|
+
def _nc_commit_confirm_testing(nr: Task) -> bool:
|
78
|
+
"""
|
79
|
+
Executes a series of tests during a NETCONF commit-confirm timeout period. This function starts a
|
80
|
+
timer, runs tests using the Nornir TestsProcessor, and prints the results along with the time taken to
|
81
|
+
complete the tests. If the tests are not successful, it waits for the specified confirm timeout period
|
82
|
+
to expire.
|
83
|
+
"""
|
84
|
+
# pylint: disable=invalid-name
|
85
|
+
|
86
|
+
# Start a timer to check how long the Nornir TestProcessor Task need
|
87
|
+
timer_start = time.time()
|
88
|
+
cfg_status = True
|
89
|
+
|
90
|
+
print_task_title("Run Nornir TestsProcessor during NETCONF commit-confirm timeout")
|
91
|
+
|
92
|
+
# Run Nornir TestsProcessor for Unit, Integration, and System tests. All tests files with the inventory
|
93
|
+
# key starting with the prefix "cfgtp_{name}_" and are loaded from the inventory.
|
94
|
+
for name in ["Unit", "Integration", "System"]:
|
95
|
+
# Run the Nornir TestsProcessor Task
|
96
|
+
if not nr_testsprocessor(nr=nr, name=name, inv_key=f"cfgtp_{name.lower()}_"):
|
97
|
+
cfg_status = False
|
98
|
+
|
99
|
+
# Print a overall TestsProcessor result
|
100
|
+
task_text = "NORNIR overall TestsProcessor result"
|
101
|
+
print(task_name(text=task_text))
|
102
|
+
print(task_result(text=task_text, changed=False, level_name="INFO" if cfg_status else "ERROR"))
|
103
|
+
print(f"'{task_text}' -> NornirResponse <Success: {'True' if cfg_status else 'False'}>")
|
104
|
+
|
105
|
+
# Print the time which Nornir TestsProcessor needed
|
106
|
+
exeeded_time = round(time.time() - timer_start, 1)
|
107
|
+
print(f"-> Nornir TestsProcessor finished in: {exeeded_time}s")
|
108
|
+
|
109
|
+
########################################### WORKAROUND ##################################################
|
110
|
+
### Wait time in case of a failure not needed at the moment due to the RESTCONF workaround ###
|
111
|
+
# If the cfg_status of the Nornir TestsProcessor is not successful
|
112
|
+
# if not cfg_status:
|
113
|
+
# remaining_timout = confirm_timeout - exeeded_time
|
114
|
+
# print(f"-> Wait remaining {remaining_timout}s for NETCONF commit confirm timeout to expire ...")
|
115
|
+
# time.sleep(remaining_timout)
|
116
|
+
#########################################################################################################
|
117
|
+
|
118
|
+
return cfg_status
|
119
|
+
|
120
|
+
|
121
|
+
def _verify_confirm_timeout(timer_start: float, confirm_timeout: int) -> bool:
|
122
|
+
"""
|
123
|
+
TBD
|
124
|
+
"""
|
125
|
+
# Set the end timer and calculate the remaining confirm-timeout
|
126
|
+
timer_end = round(time.time() - timer_start, 1)
|
127
|
+
remaining_timout = round(confirm_timeout - timer_end, 1)
|
128
|
+
|
129
|
+
# If the remaining confirm-timeout is already over after or during the commit then most likely the
|
130
|
+
# connection to the device was lost and the config-rollback happened.
|
131
|
+
if remaining_timout <= 0:
|
132
|
+
task_text = "NETCONF verify commit results"
|
133
|
+
print(task_name(text=task_text))
|
134
|
+
print(task_error(text=task_text, changed=False))
|
135
|
+
print(f"'{task_text}' -> NornirResult <Success: False>")
|
136
|
+
print(f"-> The remaining confirm-timeout is: {remaining_timout}s")
|
137
|
+
print(" - The config confirm-timeout timed out after the commit!")
|
138
|
+
print(" - Most likely the connection to the device was lost and the config-rollback happened!")
|
139
|
+
print(" - The device is now in the previous state before the commit!")
|
140
|
+
|
141
|
+
# Return False as the config-rollback timeout was already over after or during the commit
|
142
|
+
return False
|
143
|
+
|
144
|
+
# Return True and print nothing as everything is fine
|
145
|
+
return True
|
146
|
+
|
147
|
+
|
148
|
+
#### NETCONF config Workflow ################################################################################
|
149
|
+
|
150
|
+
|
151
|
+
def nc_cfg_iosxe_netconf_config(
|
152
|
+
nr: Nornir,
|
153
|
+
rebuild: str = "golden-config",
|
154
|
+
disable_commit_confirm: bool = False,
|
155
|
+
confirm_timeout: int = 120,
|
156
|
+
dry_run: bool = False,
|
157
|
+
verbose: bool = False,
|
158
|
+
) -> bool:
|
159
|
+
"""
|
160
|
+
Configures an IOS-XE device using NETCONF. This function performs a series of config steps on an
|
161
|
+
IOS-XE device using NETCONF. It handles locking the candidate datastore, applying different
|
162
|
+
config templates, validating, and committing the changes. It also supports commit-confirm
|
163
|
+
operations to run Nornir TestsProcessor device testing and dry-runs without commiting the config.
|
164
|
+
|
165
|
+
!!! NETCONF lock/unlock rpc have been commented out as the unlock fails since 17.12.X !!!
|
166
|
+
"""
|
167
|
+
# pylint: disable=invalid-name,too-many-arguments
|
168
|
+
|
169
|
+
print_task_title("Cleanup NETCONF candidate config")
|
170
|
+
|
171
|
+
# Checks if a datastore sync in ongoing and wait until is finish. Default cfg_status argument is True
|
172
|
+
cfg_status = rc_cisco_rpc_is_syncing(nr=nr, verbose=verbose)
|
173
|
+
|
174
|
+
########################################### WORKAROUND ##################################################
|
175
|
+
### It seems that since 17.12.4 the NETCONF server implementation has a bug ! ###
|
176
|
+
### - The lock/unlock rpc is not working as expected. ###
|
177
|
+
### - The unlock rpc fails with an error message / The lock rpc is working as expected ###
|
178
|
+
### - The lock is not needed for the config workflow. The lock is only needed for the rollback. ###
|
179
|
+
### - There the NETCONF rollback-on-error is not working as expected. ###
|
180
|
+
### -> Themporary workaround is to comment out the lock/unlock rpc and implement a rollback by CLI ###
|
181
|
+
#########################################################################################################
|
182
|
+
# Lock the NETCONF candidate datastore
|
183
|
+
# if not nc_lock(nr=nr, cfg_status=cfg_status, verbose=verbose):
|
184
|
+
# return False
|
185
|
+
|
186
|
+
# Cleanup configs which can't be done efficient with the Jinja2 template concept
|
187
|
+
cfg_status = nc_cfg_cleanup(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
188
|
+
|
189
|
+
if cfg_status:
|
190
|
+
print_task_title("Configure NETCONF candidate config")
|
191
|
+
|
192
|
+
# Create a dict with the template startswith string and the task text as key-value pairs
|
193
|
+
cfg_tasks = {
|
194
|
+
"tpl_base": "NETCONF configure base system payload template",
|
195
|
+
"tpl_sys": "NETCONF configure general system payload template",
|
196
|
+
}
|
197
|
+
# Configure NETCONF system config if cfg_status is still True
|
198
|
+
cfg_status = nc_cfg_tpl(nr=nr, cfg_tasks=cfg_tasks, cfg_status=cfg_status, verbose=verbose)
|
199
|
+
|
200
|
+
# Create a dict with the template startswith string and the task text as key-value pairs
|
201
|
+
cfg_tasks = {
|
202
|
+
"tpl_portchannel": "NETCONF configure portchannel interface payload template",
|
203
|
+
"tpl_int": "NETCONF configure general interface payload template",
|
204
|
+
"tpl_svi": "NETCONF configure vlan interface payload template",
|
205
|
+
}
|
206
|
+
# Continue NETCONF interface config if cfg_status is still True
|
207
|
+
cfg_status = nc_cfg_tpl_int(nr=nr, cfg_tasks=cfg_tasks, cfg_status=cfg_status, verbose=verbose)
|
208
|
+
|
209
|
+
# Print the task title basesd on the disable_commit_confirm argument and set the commit variable
|
210
|
+
if disable_commit_confirm:
|
211
|
+
print_task_title("Commit or discard NETCONF candidate config")
|
212
|
+
else:
|
213
|
+
print_task_title("Commit-confirm or discard NETCONF candidate config")
|
214
|
+
|
215
|
+
# Validate NETCONF config if cfg_status is still True
|
216
|
+
cfg_status = nc_validate(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
217
|
+
|
218
|
+
if dry_run:
|
219
|
+
_nc_exit_dry_run(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
220
|
+
|
221
|
+
########################################### WORKAROUND ##################################################
|
222
|
+
# If its a commit-confirm and the cfg_status is True
|
223
|
+
if not disable_commit_confirm and cfg_status:
|
224
|
+
# Calculate the revert-timer in minutes from the confirm-timeout in seconds
|
225
|
+
revert_timer = confirm_timeout // 60
|
226
|
+
# Replace the config with a revert-timer right before the commit
|
227
|
+
cfg_status = rc_replace_config(nr=nr, rebuild=rebuild, verbose=verbose, revert_timer=revert_timer)
|
228
|
+
#########################################################################################################
|
229
|
+
|
230
|
+
# Start a timer to check how long the commit takes.
|
231
|
+
timer_start = time.time()
|
232
|
+
|
233
|
+
########################################### WORKAROUND ##################################################
|
234
|
+
### Set confirm to 'False' with the RESTCONF workaround ###
|
235
|
+
#########################################################################################################
|
236
|
+
# Commit all changes on the NETCONF candidate datastore if cfg_status is still True
|
237
|
+
cfg_status = nc_commit(
|
238
|
+
nr=nr,
|
239
|
+
confirm=False,
|
240
|
+
confirm_timeout=confirm_timeout,
|
241
|
+
cfg_status=cfg_status,
|
242
|
+
verbose=verbose,
|
243
|
+
)
|
244
|
+
|
245
|
+
# If the revert-timer is already over after or during the commit, then most likely the connection to the
|
246
|
+
# device was lost and the config-rollback happened.
|
247
|
+
if not disable_commit_confirm:
|
248
|
+
if not _verify_confirm_timeout(timer_start=timer_start, confirm_timeout=confirm_timeout):
|
249
|
+
# Return as the config-rollback timeout was already over after or during the commit
|
250
|
+
return False
|
251
|
+
|
252
|
+
# Run some tests if its a commit-confirm no error happend on the commit
|
253
|
+
if not disable_commit_confirm and cfg_status:
|
254
|
+
# Run the Nornir TestsProcessor test suite
|
255
|
+
cfg_status = _nc_commit_confirm_testing(nr=nr)
|
256
|
+
|
257
|
+
print_task_title("Commit or discard NETCONF candidate config")
|
258
|
+
|
259
|
+
########################################### WORKAROUND ##############################################
|
260
|
+
### The is_syncing rpc and the second commit is not needed with the RESTCONF workaround ###
|
261
|
+
#####################################################################################################
|
262
|
+
# Checks if an active datastore sync in ongoing and wait until is finish if cfg_status is True
|
263
|
+
# cfg_status = rc_cisco_rpc_is_syncing(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
264
|
+
|
265
|
+
# Commit all changes on the NETCONF candidate datastore if cfg_status is still True
|
266
|
+
# cfg_status = nc_commit(nr=nr, confirm=False, cfg_status=cfg_status, verbose=verbose)
|
267
|
+
|
268
|
+
########################################### WORKAROUND ##############################################
|
269
|
+
# Confirm the revert-timer right after the commit
|
270
|
+
cfg_status = cli_confirm_or_revert_config(
|
271
|
+
nr=nr, action="confirm", cfg_status=cfg_status, verbose=verbose
|
272
|
+
)
|
273
|
+
#####################################################################################################
|
274
|
+
|
275
|
+
# Discard the NETCONF config if there happen an error on the commit or commit confirm
|
276
|
+
if not cfg_status:
|
277
|
+
# Discard all changes on the NETCONF candidate datastore
|
278
|
+
nc_discard(nr=nr, verbose=verbose)
|
279
|
+
|
280
|
+
########################################### WORKAROUND ##############################################
|
281
|
+
# Revert the config right after the discard
|
282
|
+
cli_confirm_or_revert_config(nr=nr, action="revert", cfg_status=True, verbose=verbose)
|
283
|
+
#####################################################################################################
|
284
|
+
# Unlock the NETCONF datastore
|
285
|
+
# nc_unlock(nr=nr, verbose=verbose)
|
286
|
+
|
287
|
+
return cfg_status
|
288
|
+
|
289
|
+
# Unlock the NETCONF datastore
|
290
|
+
# cfg_status = nc_unlock(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
291
|
+
|
292
|
+
# Checks if an active datastore sync in ongoing and wait until is finish if cfg_status is True
|
293
|
+
cfg_status = rc_cisco_rpc_is_syncing(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
294
|
+
|
295
|
+
# Send the Cisco save config RESTCONF RPC if cfg_status is True
|
296
|
+
cfg_status = rc_cisco_rpc_save_config(nr=nr, cfg_status=cfg_status, verbose=verbose)
|
297
|
+
|
298
|
+
return cfg_status
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
This module is a complete config management inclusive testing and rollback in case of failures for
|
4
|
+
Cisco IOS-XE devices. The Main function is intended to import and execute by other scripts.
|
5
|
+
"""
|
6
|
+
|
7
|
+
|
8
|
+
import argparse
|
9
|
+
from nornir.core.filter import F
|
10
|
+
from nornir_collection.nornir_plugins.inventory.utils import init_nornir
|
11
|
+
from nornir_collection.cisco.configuration_management.cli.show_tasks import nr_pre_config_check
|
12
|
+
from nornir_collection.cisco.configuration_management.netconf.config_workflow import (
|
13
|
+
nc_cfg_iosxe_netconf_config,
|
14
|
+
)
|
15
|
+
from nornir_collection.cisco.configuration_management.restconf.config_workflow import (
|
16
|
+
rc_update_golden_config,
|
17
|
+
rc_replace_config,
|
18
|
+
)
|
19
|
+
from nornir_collection.utils import print_task_title, task_name, task_info, task_error, exit_info, exit_error
|
20
|
+
|
21
|
+
|
22
|
+
__author__ = "Willi Kubny"
|
23
|
+
__maintainer__ = "Willi Kubny"
|
24
|
+
__version__ = "1.0"
|
25
|
+
__license__ = "MIT"
|
26
|
+
__email__ = "willi.kubny@dreyfusbank.ch"
|
27
|
+
__status__ = "Production"
|
28
|
+
|
29
|
+
|
30
|
+
def main(nr_config: str, args: argparse.Namespace) -> None:
|
31
|
+
"""
|
32
|
+
Main function is intended to import and execute by other scripts.
|
33
|
+
It initialize Nornir, configures and test the config on Cisco IOS-XE devices.
|
34
|
+
|
35
|
+
* Args:
|
36
|
+
* nr_config (str): Path to the Nornir config file.
|
37
|
+
* args (argparse.Namespace): Command-line arguments parsed by argparse.
|
38
|
+
|
39
|
+
* Steps:
|
40
|
+
* Initialize Nornir
|
41
|
+
* Verify that all filtered devices that have the tag slug 'cfg-mgmt'
|
42
|
+
* Do a pre-config check to ensure the current config is in a clean state
|
43
|
+
* Configure the network from code with NETCONF and RESTCONF
|
44
|
+
* Set the config rebuild level (Day0-Config or Golden-Config)
|
45
|
+
* Perform a RESTCONF config-rollback to the Day0-Config or Golden-Config
|
46
|
+
* Verify that there is no NETCONF sync in progress
|
47
|
+
* Lock the NETCONF datastore
|
48
|
+
* Reset all interfaces to default config
|
49
|
+
* Start NETCONF general system config
|
50
|
+
* Continue NETCONF interface config
|
51
|
+
* Validate NETCONF config
|
52
|
+
* Abort the config if a dry-run is requested
|
53
|
+
* Commit all changes on the NETCONF candidate datastore (default with commit-confirm)
|
54
|
+
* Run testing if commit-confirm was requested
|
55
|
+
* Commit again if testing was successful
|
56
|
+
* Unlock the NETCONF datastore
|
57
|
+
* Verify that there is no NETCONF sync in progress
|
58
|
+
* Save the running-config to the startup-config using RESTCONF
|
59
|
+
* Verify the status of the config results
|
60
|
+
* Update the golden-config with RESTCONF
|
61
|
+
|
62
|
+
* Exits:
|
63
|
+
* It exits with appropriate messages and statuses based on the success or failure of each step.
|
64
|
+
"""
|
65
|
+
# pylint: disable=invalid-name
|
66
|
+
|
67
|
+
#### Initialize Script and Nornir #######################################################################
|
68
|
+
|
69
|
+
# Initialize, transform and filter the Nornir inventory are return the filtered Nornir object
|
70
|
+
# Define data to load from NetBox in addition to the base Nornir inventory plugin
|
71
|
+
add_netbox_data = {"load_virtual_chassis_data": True, "load_interface_data": True, "load_vlan_data": True}
|
72
|
+
nr = init_nornir(config_file=nr_config, args=args, add_netbox_data=add_netbox_data)
|
73
|
+
|
74
|
+
# Filter the Nornir inventory again only with devices that have the tag slug 'cfg-mgmt' and compare the
|
75
|
+
# filtered inventory with the original inventory to prevent the script from running on devices that are
|
76
|
+
# not intended for config management
|
77
|
+
print_task_title(title="Verify Nornir inventory filter for CFG-MGMT")
|
78
|
+
task_text = "NORNIR verify inventory filter for CFG-MGMT"
|
79
|
+
print(task_name(text=task_text))
|
80
|
+
# Filter the Nornir inventory with devices that have the tag 'cfg-mgmt'
|
81
|
+
nr_cfg_mgmt = nr.filter(F(tags__contains="cfg-mgmt"))
|
82
|
+
# Exit the script if the filtered inventory does not match the original inventory
|
83
|
+
if len(nr.inventory.hosts) != len(nr_cfg_mgmt.inventory.hosts):
|
84
|
+
print(task_error(text=task_text, changed=False))
|
85
|
+
print(f"'{task_text}' -> NornirResult <Success: False>")
|
86
|
+
exit_error(
|
87
|
+
task_text=task_text,
|
88
|
+
text="ALERT: INVENTORY FILTER MISMATCH FOR CFG-MGMT!",
|
89
|
+
msg=[
|
90
|
+
"-> The filtered inventory does not match the original inventory",
|
91
|
+
"-> Ensure all devices intended for config management are tagged with 'CFG-MGMT'",
|
92
|
+
],
|
93
|
+
)
|
94
|
+
print(task_info(text=task_text, changed=False))
|
95
|
+
print(f"'{task_text}' -> NornirResponse <Success: True>")
|
96
|
+
print("-> All filtered devices are tagged with 'CFG-MGMT'")
|
97
|
+
|
98
|
+
#### Run Nornir Tasks to Verify the config State ########################################################
|
99
|
+
|
100
|
+
# First do a pre-config check to ensure the current config is in a clean state
|
101
|
+
if not args.rebuild and not args.skip_pre_check:
|
102
|
+
cfg_status = nr_pre_config_check(nr=nr)
|
103
|
+
# Exit the script if the config status is not clean
|
104
|
+
if not cfg_status:
|
105
|
+
task_text = "Verify pre-config check results"
|
106
|
+
print_task_title(title=task_text)
|
107
|
+
print(f"{task_name(text=task_text)}")
|
108
|
+
exit_error(
|
109
|
+
task_text=task_text,
|
110
|
+
text="BAD NEWS! THE RUNNING-CONFIG IS NOT CLEAN!",
|
111
|
+
msg=[
|
112
|
+
"-> Bring the running-config into a clean state with the golden-config",
|
113
|
+
"-> Or skip the pre-config check",
|
114
|
+
],
|
115
|
+
)
|
116
|
+
|
117
|
+
#### Run Nornir Tasks to Replace the config #############################################################
|
118
|
+
|
119
|
+
# If its not a NETCONF dry-run, replace the current config with the golden-config or day0-config
|
120
|
+
if not args.dryrun:
|
121
|
+
# Replace the config with a Cisco specific RESTCONF RPC. Default cfg_status argument is True
|
122
|
+
cfg_status = rc_replace_config(nr=nr, rebuild=args.rebuild, verbose=args.verbose, revert_timer=None)
|
123
|
+
|
124
|
+
# Exit the script if the RESTCONF replace-config failed
|
125
|
+
if not cfg_status:
|
126
|
+
task_text = "Verify RESTCONF replace-config results"
|
127
|
+
print_task_title(title=task_text)
|
128
|
+
print(f"{task_name(text=task_text)}")
|
129
|
+
exit_error(
|
130
|
+
task_text=task_text,
|
131
|
+
text="ALERT: REPLACE-CONFIG HAVE FAILED!",
|
132
|
+
msg=[
|
133
|
+
"-> RESTCONF failed to replace the current config",
|
134
|
+
"-> The remaining tasks have been omitted due to RESTCONF failed",
|
135
|
+
],
|
136
|
+
)
|
137
|
+
|
138
|
+
#### Run Nornir Tasks to Configure IOS-XE device from Code with NETCONF #################################
|
139
|
+
|
140
|
+
# The IOS-XE device will be reconfigured to the desired state and return a boolian (True == Successful)
|
141
|
+
cfg_status = nc_cfg_iosxe_netconf_config(
|
142
|
+
nr=nr,
|
143
|
+
rebuild=args.rebuild,
|
144
|
+
disable_commit_confirm=args.disable_commit_confirm,
|
145
|
+
confirm_timeout=args.confirm_timeout,
|
146
|
+
dry_run=args.dryrun,
|
147
|
+
verbose=args.verbose,
|
148
|
+
)
|
149
|
+
|
150
|
+
# Exit the script if the NETCONF config failed
|
151
|
+
if not cfg_status:
|
152
|
+
# Replace the config with a Cisco specific RESTCONF RPC. Default cfg_status argument is True
|
153
|
+
# This ensures that the golden-config is not updated if the NETCONF config failed
|
154
|
+
rc_replace_config(nr=nr, rebuild=args.rebuild, verbose=args.verbose, revert_timer=None)
|
155
|
+
|
156
|
+
# Verify status of the config results
|
157
|
+
task_text = "Verify NETCONF config results"
|
158
|
+
print_task_title(title=task_text)
|
159
|
+
print(f"{task_name(text=task_text)}")
|
160
|
+
exit_error(
|
161
|
+
task_text=task_text,
|
162
|
+
text="ALERT: ONE OR MORE CONFIGS HAVE FAILED!",
|
163
|
+
msg=[
|
164
|
+
"-> NETCONF failed to apply the desired config",
|
165
|
+
"-> The remaining tasks have been omitted due to NETCONF failed",
|
166
|
+
"-> The current config is unchanged and the golden-config have not been updated yet",
|
167
|
+
],
|
168
|
+
)
|
169
|
+
|
170
|
+
#### Run Nornir Tasks to Update the Golden-config #######################################################
|
171
|
+
|
172
|
+
# Update the golden config with RESTCONF or exit the script if RESTCONF failed
|
173
|
+
rc_update_golden_config(nr=nr, verbose=args.verbose)
|
174
|
+
|
175
|
+
# If rc_update_golden_config didn't exit the script, everything was successful
|
176
|
+
task_text = "Verify config results"
|
177
|
+
print_task_title(title=task_text)
|
178
|
+
print(f"{task_name(text=task_text)}")
|
179
|
+
exit_info(
|
180
|
+
task_text=task_text,
|
181
|
+
text="GOOD NEWS! ALL CONFIGS HAVE BEEN APPLIED SUCCESSFUL!",
|
182
|
+
msg=[
|
183
|
+
"-> The desired NETCONF config have been activated and saved",
|
184
|
+
"-> The golden-config have been updated",
|
185
|
+
],
|
186
|
+
)
|