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
File without changes
File without changes
@@ -0,0 +1,358 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ This module contains general functions and tasks related to Batfish.
4
+
5
+ The functions are ordered as followed:
6
+ - Batfish Helper Functions
7
+ - Nornir Batfish Tasks
8
+ - Nornir Batfish Tasks in regular Function
9
+ """
10
+
11
+ from pybatfish.client.session import Session
12
+ from nornir.core import Nornir
13
+ from nornir.core.task import Task, Result
14
+ from nornir_collection.batfish.utils import (
15
+ batfish_question_failed,
16
+ batfish_assert_type_failed,
17
+ batfish_exit_error,
18
+ )
19
+ from nornir_collection.utils import print_result, task_result, list_flatten, get_dict_value_by_path
20
+
21
+
22
+ #### Batfish Helper Functions ################################################################################
23
+
24
+
25
+ def batfish_assert_cfg_prop(task: Task, data: tuple, name_add: str = False) -> list:
26
+ """
27
+ Batfish assert helper task to assert the ref_prop against the cfg_prop based on the ref_prop data type.
28
+ The col_name specifies the configuration property which should be asked to Batfish.
29
+ """
30
+ # Extract the variables from the data tuple
31
+ col_name, ref_prop, cfg_prop = data
32
+ # Set the name_add variable if exists, else col_name
33
+ name_add = name_add if name_add else col_name
34
+
35
+ if isinstance(ref_prop, str):
36
+ # Define the property in the snapshot
37
+ snap_prop = cfg_prop[col_name].to_string(index=False)
38
+ snap_prop = snap_prop.rstrip()
39
+ snap_prop = snap_prop.lstrip()
40
+ # Set the Nornir task failed variable
41
+ failed = bool(ref_prop != snap_prop)
42
+ cfg_result = f"-> Expected: '{ref_prop}'\n" f"-> Configured: '{snap_prop}'"
43
+
44
+ elif isinstance(ref_prop, list):
45
+ ref_prop = list_flatten(ref_prop)
46
+ # Define the property in the snapshot
47
+ snap_prop = list_flatten(cfg_prop[col_name].tolist())
48
+ snap_prop = [str(x) for x in snap_prop]
49
+ # Find extra and missing referency properties
50
+ ref_prop_extra = [x for x in snap_prop if x not in ref_prop]
51
+ ref_prop_missing = [x for x in ref_prop if x not in snap_prop]
52
+ # Set the Nornir task failed variable
53
+ failed = bool(ref_prop_extra + ref_prop_missing)
54
+ cfg_result = (
55
+ f"-> Expected: {ref_prop}\n"
56
+ f"-> Missing (to add): {ref_prop_missing if ref_prop_missing else '[]'}\n"
57
+ f"-> Extra (to remove): {ref_prop_extra if ref_prop_extra else '[]'}"
58
+ )
59
+
60
+ else:
61
+ # Set the Nornir task failed variable
62
+ failed = True
63
+ cfg_result = (
64
+ f"->'ref_prop' argument type {type(ref_prop)} is not implemented to assert\n"
65
+ f"-> Update the function _batfish_assert_cfg_prop() to support this 'ref_prop' data type"
66
+ )
67
+
68
+ # Set the Nornir result to return
69
+ level_name = "ERROR" if failed else "INFO"
70
+ result = (
71
+ f"{task_result(text=f'{task.name} {name_add}', changed=False, level_name=level_name)}\n"
72
+ f"'{task.name} {col_name}' -> BatfishResponse <Success: {not failed}>\n"
73
+ f"{cfg_result}"
74
+ )
75
+
76
+ return result, failed
77
+
78
+
79
+ def batfish_get_ref_props_from_nr_inv(task: Task, inv_key: str) -> dict:
80
+ """
81
+ Loop over all hosts keys to find keys which starts with the inv_startswith string and add the values
82
+ to a dict. Then return this dict which should contain all ref_props data.
83
+ """
84
+ ref_props = {}
85
+ # Loop over all hosts keys to find keys which starts with the inv_startswith string
86
+ for key, value in task.host.items():
87
+ if key.startswith(inv_key):
88
+ # Update the ref_props dict with the value
89
+ ref_props.update(value)
90
+
91
+ return ref_props
92
+
93
+
94
+ #### Nornir Batfish Tasks ####################################################################################
95
+
96
+
97
+ def batfish_assert_cfg_node_property_task(task: Task, nr_inv: bool, data: tuple[Session, dict]) -> Result:
98
+ """
99
+ Nornir task to assert Batfish node properties agains values from the Nornir inventory or direct specified
100
+ values in the ref_props dict. The ref_props argument in the data tuple specifies the Batfish node property
101
+ question to ask as the key The value can be the Nornir inventory which have to be added as a map list
102
+ of the Nornir inventory dict keys if nr_inv is True or the correct value have to be specified if nr_inv
103
+ is False.
104
+
105
+ ref_props = {
106
+ "Domain_Name": ["cfg_domain_name"],
107
+ "NTP_Servers": ["cfg_ntp", "server"],
108
+ "NTP_Source_Interface": ["cfg_ntp", "source"],
109
+ }
110
+ """
111
+ # pylint: disable=invalid-name
112
+
113
+ # Extract the variables from the data tuple
114
+ bf, ref_props = data
115
+
116
+ # If the ref_props is a string to specify the inventory startswith key, then create a dict with all
117
+ # inventory keys which start with this string (nested dict not supported)
118
+ if isinstance(ref_props, str):
119
+ ref_props = batfish_get_ref_props_from_nr_inv(task=task, inv_key=ref_props)
120
+
121
+ # Set the initial Nornir Result object variables
122
+ result = []
123
+ failed = False
124
+
125
+ # Extract the node properties for the host
126
+ cfg_prop = bf.q.nodeProperties(nodes=str(task.host)).answer().frame()
127
+
128
+ # If the cfg_prop dataframe is empty
129
+ if cfg_prop.empty:
130
+ subresult, subresult_failed = batfish_question_failed(task=task, df=cfg_prop)
131
+ # Add the subresult to the Nornir result list
132
+ result.append(subresult)
133
+ # Return the Nornir result
134
+ return Result(host=task.host, result=result, failed=True)
135
+
136
+ # Loop over each column name, reference property key-value pair in the dict
137
+ for col_name, ref_prop in ref_props.items():
138
+ if nr_inv:
139
+ # Get the value from the Nornir inventory with the ref_prop map list
140
+ ref_prop = get_dict_value_by_path(data_dict=task.host, map_list=ref_prop)
141
+
142
+ # Create a tuple with all needed data to assert the Batfish question
143
+ data = (col_name, ref_prop, cfg_prop)
144
+
145
+ # Assert the correct ref_prop type
146
+ if isinstance(ref_prop, (str, list)):
147
+ subresult, subresult_failed = batfish_assert_cfg_prop(task=task, data=data)
148
+ else:
149
+ data = (col_name, ref_prop, "'str' or 'list'")
150
+ subresult, subresult_failed = batfish_assert_type_failed(task=task, data=data)
151
+
152
+ # Add the subresult to the Nornir result list
153
+ result.append(subresult)
154
+ if subresult_failed:
155
+ failed = True
156
+
157
+ # Return the Nornir result
158
+ return Result(host=task.host, result=result, failed=failed)
159
+
160
+
161
+ def batfish_assert_cfg_interface_property_task(
162
+ task: Task, nr_inv: bool, data: tuple[Session, dict]
163
+ ) -> Result:
164
+ """
165
+ Nornir task to assert Batfish interface properties agains values from the Nornir inventory or direct
166
+ specified values in the ref_props dict. The ref_props argument in the data tuple specifies a dict for each
167
+ interface with the Batfish interface property question to ask as the key. The value can be the Nornir
168
+ inventory which have to be added as a map list of the Nornir inventory dict keys if nr_inv is True or
169
+ the correct value have to be specified if nr_inv is False.
170
+
171
+ ref_props = {
172
+ "FortyGigabitEthernet1/1/1" : {
173
+ "Switchport_Trunk_Encapsulation" : "DOT1Q",
174
+ "Admin_Up" : "True",
175
+ "Active" : "True",
176
+ }
177
+ "FortyGigabitEthernet1/1/2" : {
178
+ "Switchport_Trunk_Encapsulation" : "DOT1Q",
179
+ "Admin_Up" : "True",
180
+ "Active" : "True",
181
+ }
182
+ }
183
+ """
184
+ # pylint: disable=invalid-name
185
+
186
+ # Extract the variables from the data tuple
187
+ bf, ref_props = data
188
+
189
+ # If the Nornir inventory should be used and ref_props is a string to specify the inventory startswith
190
+ # key, then create a dict with all inventory keys which start with this string (nested dict not supported)
191
+ if nr_inv and isinstance(ref_props, str):
192
+ ref_props = batfish_get_ref_props_from_nr_inv(task=task, inv_key=ref_props)
193
+
194
+ # Set the initial Nornir Result object variables
195
+ result = []
196
+ failed = False
197
+
198
+ # Loop over each interface
199
+ for interface in ref_props.keys():
200
+ # Extract the interface properties for the host
201
+ cfg_prop = bf.q.interfaceProperties(nodes=str(task.host), interfaces=interface).answer().frame()
202
+
203
+ # If the cfg_prop dataframe is empty
204
+ if cfg_prop.empty:
205
+ subresult, subresult_failed = batfish_question_failed(task=task, df=cfg_prop, name_add=interface)
206
+ # Add the subresult to the Nornir result list
207
+ result.append(subresult)
208
+ if subresult_failed:
209
+ failed = True
210
+ else:
211
+ # Loop over each column name, reference property key-value pair in the dict
212
+ for col_name, ref_prop in ref_props[interface].items():
213
+ if nr_inv:
214
+ # Get the value from the Nornir inventory with the ref_prop map list
215
+ ref_prop = get_dict_value_by_path(data_dict=task.host, map_list=ref_prop)
216
+
217
+ # Create a tuple with all needed data to assert the Batfish question
218
+ data = (col_name, ref_prop, cfg_prop)
219
+
220
+ # Assert the correct ref_prop type
221
+ if isinstance(ref_prop, (str, list)):
222
+ subresult, subresult_failed = batfish_assert_cfg_prop(
223
+ task=task, data=data, name_add=interface
224
+ )
225
+ else:
226
+ data = (col_name, ref_prop, "'str' or 'list'")
227
+ subresult, subresult_failed = batfish_assert_type_failed(
228
+ task=task, data=data, name_add=interface
229
+ )
230
+
231
+ # Add the subresult to the Nornir result list
232
+ result.append(subresult)
233
+ if subresult_failed:
234
+ failed = True
235
+
236
+ # Return the Nornir result
237
+ return Result(host=task.host, result=result, failed=failed)
238
+
239
+
240
+ def batfish_assert_cfg_switched_vlan_property_task(
241
+ task: Task, nr_inv: bool, data: tuple[Session, dict]
242
+ ) -> Result:
243
+ """
244
+ Nornir task to assert Batfish switched vlan properties agains values from the Nornir inventory or direct
245
+ specified values in the ref_props dict. The ref_props argument in the data tuple specifies the Batfish
246
+ node property question to ask as the key The value can be the Nornir inventory which have to be added
247
+ as a map list of the Nornir inventory dict keys if nr_inv is True or the correct value have to be
248
+ specified if nr_inv is False.
249
+
250
+ ref_props = {
251
+ "VLAN_ID": ["cfg_vlans"],
252
+ "VLAN_ID_ADD": ["cfg_vlans_add"],
253
+ }
254
+ """
255
+ # pylint: disable=invalid-name
256
+
257
+ # Extract the variables from the data tuple
258
+ bf, ref_props = data
259
+
260
+ # If the Nornir inventory should be used and ref_props is a string to specify the inventory startswith
261
+ # key, then create a dict with all inventory keys which start with this string (nested dict not supported)
262
+ if nr_inv and isinstance(ref_props, str):
263
+ ref_props = batfish_get_ref_props_from_nr_inv(task=task, inv_key=ref_props)
264
+
265
+ # Set the initial Nornir Result object variables
266
+ result = []
267
+ failed = False
268
+
269
+ # Extract the node properties for the host
270
+ cfg_prop = bf.q.switchedVlanProperties(nodes=str(task.host)).answer().frame()
271
+
272
+ # If the cfg_prop dataframe is empty
273
+ if cfg_prop.empty:
274
+ subresult, subresult_failed = batfish_question_failed(task=task, df=cfg_prop)
275
+ # Add the subresult to the Nornir result list
276
+ result.append(subresult)
277
+ # Return the Nornir result
278
+ return Result(host=task.host, result=result, failed=True)
279
+
280
+ # Loop over each column name, reference property key-value pair in the dict
281
+ for col_name, ref_prop in ref_props.items():
282
+ if nr_inv:
283
+ # Get the value from the Nornir inventory with the ref_prop map list
284
+ ref_prop = get_dict_value_by_path(data_dict=task.host, map_list=ref_prop)
285
+ # If the Nornir inventory is a dict, assume that the key is the vlan number and create a list
286
+ if isinstance(ref_prop, dict):
287
+ ref_prop = [str(vlan) for vlan in ref_prop.keys()]
288
+ # If the custom column name VLAN_ID_ADD exists in the ref_prop, then add these vlans to the list
289
+ if "VLAN_ID_ADD" in ref_prop:
290
+ # Get the value from the Nornir inventory with the ref_prop map list
291
+ ref_prop_add = get_dict_value_by_path(data_dict=task.host, map_list=ref_prop["VLAN_ID_ADD"])
292
+ # If the Nornir inventory is a dict, assume that the key is the vlan number and create a list
293
+ if isinstance(ref_prop_add, dict):
294
+ ref_prop_add = [str(vlan) for vlan in ref_prop_add.keys()]
295
+ # Add both vlan lists together
296
+ ref_prop = ref_prop + ref_prop_add
297
+
298
+ # Add vlan 1 as it's the default and can't be deleted
299
+ ref_prop = ["1"] + ref_prop
300
+
301
+ # Create a tuple with all needed data to assert the Batfish question
302
+ data = (col_name, ref_prop, cfg_prop)
303
+
304
+ # Assert the correct ref_prop type
305
+ if isinstance(ref_prop, list):
306
+ subresult, subresult_failed = batfish_assert_cfg_prop(task=task, data=data)
307
+ else:
308
+ data = (col_name, ref_prop, "'list'")
309
+ subresult, subresult_failed = batfish_assert_type_failed(task=task, data=data)
310
+
311
+ # Add the subresult to the Nornir result list
312
+ result.append(subresult)
313
+ if subresult_failed:
314
+ failed = True
315
+
316
+ # Return the Nornir result
317
+ return Result(host=task.host, result=result, failed=failed)
318
+
319
+
320
+ #### Nornir Batfish Tasks in regular Function ################################################################
321
+
322
+
323
+ def batfish_assert_config_property(nr: Nornir, nr_inv: bool, data: tuple, soft: bool = False) -> Result:
324
+ """
325
+ This function runs a Nornir task to ask Batfish configuration properties. The batfish session, the batfish
326
+ question and the ref_props dict according to the specified batfish question have to be specified as the
327
+ data tuple. The nr_inv argument specified is the values to assert should be loaded from the Nornir
328
+ inventory by a dict key map list or are specified already directly correct.
329
+ The result is printed in Nornir style and in case of an assert error the script exits with error code 1.
330
+ """
331
+ # pylint: disable=invalid-name
332
+
333
+ # Extract the variables from the data tuple
334
+ bf, bf_question, ref_props = data
335
+
336
+ # Map list to identify which Nornir task to execute for the correct Batfish question
337
+ batfish_config_property_task = {
338
+ "node": batfish_assert_cfg_node_property_task,
339
+ "interface": batfish_assert_cfg_interface_property_task,
340
+ "vlan": batfish_assert_cfg_switched_vlan_property_task,
341
+ }
342
+
343
+ # Run the Nornir task to assert Batfish configuration properties
344
+ result = nr.run(
345
+ task=batfish_config_property_task[bf_question],
346
+ name=f"BATFISH query {bf_question}",
347
+ nr_inv=nr_inv,
348
+ data=(bf, ref_props),
349
+ on_failed=True,
350
+ )
351
+
352
+ # Print the Nornir task result
353
+ print_result(result=result, result_sub_list=True)
354
+
355
+ if not soft:
356
+ # If the task failed exit with error code 1
357
+ if result.failed:
358
+ batfish_exit_error(result=result, bf_question="config")
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ This module contains general functions and tasks related to Batfish.
4
+
5
+ The functions are ordered as followed:
6
+ - Batfish Initialize Function
7
+ - Batfish Helper Functions
8
+ """
9
+
10
+ import logging
11
+ from io import StringIO
12
+ from typing import Literal
13
+ import requests
14
+ from pybatfish.client.session import Session
15
+ from pandas import DataFrame
16
+ from nornir.core.task import Task, AggregatedResult
17
+ from nornir_collection.utils import print_task_name, task_result, task_error, task_info, exit_error
18
+
19
+
20
+ #### Batfish Initialize Function #############################################################################
21
+
22
+
23
+ def init_batfish(bf_data: tuple, bf_log_lvl: Literal["WARN", "ERROR"] = "ERROR") -> Session:
24
+ """
25
+ TBD
26
+ """
27
+ # pylint: disable=invalid-name
28
+
29
+ # Extract the variables from the bf_data tuple
30
+ bf_host, bf_network, SNAPSHOT_DIR, SNAPSHOT_NAME = bf_data
31
+
32
+ task_text = "BATFISH initialize snapshot"
33
+ print_task_name(task_text)
34
+
35
+ # Replace logging.WARN with the preferred logging level
36
+ logging_lvl = logging.WARN if bf_log_lvl == "WARN" else logging.ERROR
37
+ logging.getLogger("pybatfish").setLevel(logging_lvl) # Or WARN for more details
38
+
39
+ try:
40
+ # Connect to the batfish service docker container
41
+ bf = Session(host=bf_host)
42
+ # Set batfish network logical name
43
+ bf.set_network(bf_network)
44
+ # Initialize a snapshot
45
+ bf.init_snapshot(SNAPSHOT_DIR, name=SNAPSHOT_NAME, overwrite=True)
46
+
47
+ except requests.exceptions.ConnectionError as error:
48
+ print(task_error(text=task_text, changed=False))
49
+ print(f"'{task_text}' -> BatfishResponse <Success: False>")
50
+ print(f"-> {error}")
51
+ # Exit the script with a proper message
52
+ exit_error(
53
+ task_text=task_text,
54
+ text=f"ALERT: {task_text.upper()} FAILED!",
55
+ msg="-> Analyse the Batfish docker container and snapshot settings to identify the root cause",
56
+ )
57
+
58
+ # Print the result as successful
59
+ print(task_info(text=task_text, changed=False))
60
+ print(f"'{task_text}' -> BatfishResponse <Success: True>")
61
+ print(f"-> Snapshot dir: {SNAPSHOT_DIR} / Snapshot name: {SNAPSHOT_NAME}")
62
+
63
+ return bf
64
+
65
+
66
+ #### Batfish Helper Functions ################################################################################
67
+
68
+
69
+ def batfish_question_failed(task: Task, df: DataFrame, name_add: str = False) -> None:
70
+ """
71
+ TBD
72
+ """
73
+ # pylint: disable=invalid-name
74
+
75
+ # Set the name_add variable if exists, else an empty string
76
+ name_add = name_add if name_add else ""
77
+
78
+ # df.info() prints by default directly to sys.stdout and by using the writable buffer a StringIO
79
+ # instance can be used to get the string and write it into a normal variable
80
+ buf = StringIO()
81
+ df.info(buf=buf)
82
+ df_info = buf.getvalue()
83
+ # Set the Nornir task failed and result variable
84
+ failed = True
85
+ result = (
86
+ f"{task_result(text=f'{task.name} {name_add}', changed=False, level_name='ERROR')}\n"
87
+ f"'{task.name}' -> BatfishResponse <Success: False>\n"
88
+ f"-> Batfish question returned an empty pandas dataframe\n"
89
+ f"-> Verify Batfish snapshot config hostname and Nornir hostname\n\n"
90
+ f"{df_info}"
91
+ )
92
+
93
+ return result, failed
94
+
95
+
96
+ def batfish_assert_type_failed(task: Task, data: tuple, name_add: str = False) -> None:
97
+ """
98
+ Helper function to get the error result string in case the Batfish ref_prop is an unsupported data type.
99
+ """
100
+ # Extract the variables from the data tuple
101
+ col_name, ref_prop, sup_type = data
102
+ # Set the name_add variable if exists, else col_name
103
+ name_add = name_add if name_add else col_name
104
+
105
+ # Set the Nornir task failed and result variable
106
+ failed = True
107
+ result = (
108
+ f"{task_result(text=f'{task.name} {name_add}', changed=False, level_name='ERROR')}\n"
109
+ f"'{task.name} {col_name}' -> BatfishResponse <Success: False>\n"
110
+ f"-> Unsupported 'ref_prop' argument type {type(ref_prop)}\n"
111
+ f"-> Supported 'ref_prop' argument type is {sup_type}"
112
+ )
113
+
114
+ return result, failed
115
+
116
+
117
+ def batfish_exit_error(result: AggregatedResult, bf_question: str) -> None:
118
+ """
119
+ Helper function to exit the script is case of a Batfish assert error.
120
+ """
121
+ if "config" in bf_question:
122
+ text = "Inconsistent configuration properties exists!"
123
+ msg = "-> Verify the Nornir inventory for inconsistent configuration properties"
124
+
125
+ exit_error(
126
+ task_text=result.name,
127
+ text=text,
128
+ msg=msg,
129
+ )
File without changes