Skip to content

Commit 4f564d0

Browse files
committed
Fix the issue of support bulk creation of port channels — more than 20 ports per device in a single operation.
1 parent a04c5ba commit 4f564d0

File tree

1 file changed

+251
-16
lines changed

1 file changed

+251
-16
lines changed

plugins/modules/sda_host_port_onboarding_workflow_manager.py

Lines changed: 251 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from __future__ import absolute_import, division, print_function
77

88
__metaclass__ = type
9-
__author__ = "Rugvedi Kapse, Madhan Sankaranarayanan"
9+
__author__ = "Rugvedi Kapse, Madhan Sankaranarayanan, Abhishek Maheshwari"
1010
DOCUMENTATION = r"""
1111
---
1212
module: sda_host_port_onboarding_workflow_manager
@@ -39,7 +39,7 @@
3939
extends_documentation_fragment:
4040
- cisco.dnac.workflow_manager_params
4141
author: Rugvedi Kapse (@rukapse) Madhan Sankaranarayanan
42-
(@madhansansel)
42+
(@madhansansel) Abhishek Maheshwari (@abmahesh)
4343
options:
4444
config_verify:
4545
description: Set to True to verify the Cisco Catalyst
@@ -53,6 +53,16 @@
5353
type: str
5454
choices: [merged, deleted]
5555
default: merged
56+
sda_fabric_port_channel_limit:
57+
description: >
58+
Number of port channels to be processed in a single batch
59+
when performing add/update/delete operations. If the number
60+
of port channels in the request exceeds this limit, the module
61+
will process them in sequential batches of this size.
62+
This helps manage large configurations without overwhelming
63+
the system.
64+
type: int
65+
default: 20
5666
config:
5767
description:
5868
- A list containing detailed configurations for
@@ -4233,7 +4243,6 @@ def get_vlans_and_ssids_mapped_to_vlans(self, fabric_id):
42334243
return vlans_and_ssids_mapped_to_vlans
42344244

42354245
except Exception as e:
4236-
# Log an error message and fail if an exception occurs
42374246
self.msg = (
42384247
"An error occurred while retrieving VLANs and SSIDs mapped to VLANs "
42394248
"Details using SDA - 'retrieve_the_vlans_and_ssids_mapped_to_the_vlan_within_a_fabric_site' "
@@ -4742,17 +4751,88 @@ def add_port_channels(self, add_port_channels_params):
47424751
dict: The task ID from the API call.
47434752
Description:
47444753
This method initiates the task to add port channels using the provided parameters and returns the task ID.
4754+
The method processes port channels in batches of 20 sequentially, waiting for each batch to complete.
47454755
"""
4756+
payload = add_port_channels_params.get("payload", [])
4757+
batch_size = self.params.get("sda_fabric_port_channel_limit", 20)
4758+
4759+
# If payload has 20 or fewer items, process normally
4760+
if len(payload) <= batch_size:
4761+
self.log(
4762+
"Processing {0} port channels in single batch".format(len(payload)),
4763+
"INFO",
4764+
)
4765+
return self.get_taskid_post_api_call(
4766+
"sda", "add_port_channels", add_port_channels_params
4767+
)
4768+
4769+
# Process in batches sequentially
47464770
self.log(
4747-
"Initiating addition of port channels with parameters: {0}".format(
4748-
add_port_channels_params
4771+
"Processing {0} port channels in batches of {1} sequentially".format(
4772+
len(payload), batch_size
47494773
),
47504774
"INFO",
47514775
)
4752-
return self.get_taskid_post_api_call(
4753-
"sda", "add_port_channels", add_port_channels_params
4776+
4777+
final_task_id = None
4778+
successful_batches = 0
4779+
4780+
self.log("Starting batch processing for port channel addition.", "DEBUG")
4781+
for i in range(0, len(payload), batch_size):
4782+
batch = payload[i:i + batch_size]
4783+
batch_params = {"payload": batch}
4784+
batch_number = (i // batch_size) + 1
4785+
self.log(
4786+
"Processing batch {0} with {1} port channels sequentially".format(
4787+
batch_number, len(batch)
4788+
),
4789+
"DEBUG",
4790+
)
4791+
4792+
task_id = self.get_taskid_post_api_call(
4793+
"sda", "add_port_channels", batch_params
4794+
)
4795+
4796+
self.log(
4797+
"Batch {0} API call completed, Task ID: {1}. Waiting for task completion...".format(
4798+
batch_number, task_id
4799+
),
4800+
"INFO",
4801+
)
4802+
4803+
task_name = "Add Port Channel(s) Task - Batch {0}".format(batch_number)
4804+
batch_msg = "Batch {0} with {1} port channels has completed successfully.".format(
4805+
batch_number, len(batch)
4806+
)
4807+
4808+
self.log("Checking task status for batch {0}.".format(batch_number), "DEBUG")
4809+
self.get_task_status_from_tasks_by_id(task_id, task_name, batch_msg)
4810+
4811+
if self.status == "success":
4812+
successful_batches += 1
4813+
final_task_id = task_id
4814+
self.log(
4815+
"Batch {0} completed successfully. Proceeding to next batch...".format(batch_number),
4816+
"INFO",
4817+
)
4818+
else:
4819+
self.log(
4820+
"Batch {0} failed with status: {1}. Stopping further processing.".format(
4821+
batch_number, self.status
4822+
),
4823+
"ERROR",
4824+
)
4825+
return task_id
4826+
4827+
self.log(
4828+
"Sequential port channel addition completed. Successful batches: {0}".format(
4829+
successful_batches
4830+
),
4831+
"INFO",
47544832
)
47554833

4834+
return final_task_id
4835+
47564836
def update_port_channels(self, update_port_channels_params):
47574837
"""
47584838
Initiates the task to update port channels.
@@ -4762,17 +4842,89 @@ def update_port_channels(self, update_port_channels_params):
47624842
dict: The task ID from the API call.
47634843
Description:
47644844
This method initiates the task to update port channels using the provided parameters and returns the task ID.
4845+
This method processes port channels in batches of 20 sequentially, waiting for each batch to complete.
47654846
"""
4847+
payload = update_port_channels_params.get("payload", [])
4848+
batch_size = self.params.get("sda_fabric_port_channel_limit", 20)
4849+
4850+
if len(payload) <= batch_size:
4851+
self.log(
4852+
"Processing {0} port channels in single batch".format(len(payload)),
4853+
"INFO",
4854+
)
4855+
return self.get_taskid_post_api_call(
4856+
"sda", "update_port_channels", update_port_channels_params
4857+
)
4858+
47664859
self.log(
4767-
"Initiating update of port channels with parameters: {0}".format(
4768-
update_port_channels_params
4860+
"Processing {0} port channels in batches of {1} sequentially".format(
4861+
len(payload), batch_size
47694862
),
47704863
"INFO",
47714864
)
4772-
return self.get_taskid_post_api_call(
4773-
"sda", "update_port_channels", update_port_channels_params
4865+
4866+
final_task_id = None
4867+
successful_batches = 0
4868+
4869+
self.log("Starting batch processing for port channel updates.", "DEBUG")
4870+
for i in range(0, len(payload), batch_size):
4871+
batch = payload[i:i + batch_size]
4872+
batch_params = {"payload": batch}
4873+
batch_number = (i // batch_size) + 1
4874+
4875+
self.log(
4876+
"Processing batch {0} with {1} port channels sequentially".format(
4877+
batch_number, len(batch)
4878+
),
4879+
"INFO",
4880+
)
4881+
4882+
# Execute the API call for this batch
4883+
task_id = self.get_taskid_post_api_call(
4884+
"sda", "update_port_channels", batch_params
4885+
)
4886+
4887+
self.log(
4888+
"Batch {0} API call completed, Task ID: {1}. Waiting for task completion...".format(
4889+
batch_number, task_id
4890+
),
4891+
"INFO",
4892+
)
4893+
4894+
# Wait for this batch to complete before proceeding
4895+
task_name = "Update Port Channel(s) Task - Batch {0}".format(batch_number)
4896+
batch_msg = "Batch {0} with {1} port channels has completed successfully.".format(
4897+
batch_number, len(batch)
4898+
)
4899+
4900+
self.log("Checking task status for batch {0}.".format(batch_number), "DEBUG")
4901+
self.get_task_status_from_tasks_by_id(task_id, task_name, batch_msg)
4902+
4903+
if self.status == "success":
4904+
successful_batches += 1
4905+
final_task_id = task_id # Keep the last successful task ID
4906+
self.log(
4907+
"Batch {0} completed successfully. Proceeding to next batch...".format(batch_number),
4908+
"INFO",
4909+
)
4910+
else:
4911+
self.log(
4912+
"Batch {0} failed with status: {1}. Stopping further processing.".format(
4913+
batch_number, self.status
4914+
),
4915+
"ERROR",
4916+
)
4917+
return task_id
4918+
4919+
self.log(
4920+
"Sequential port channel update completed. Successful batches: {0}".format(
4921+
successful_batches
4922+
),
4923+
"INFO",
47744924
)
47754925

4926+
return final_task_id
4927+
47764928
def delete_port_channels(self, delete_port_channel_param):
47774929
"""
47784930
Initiates the task to delete port channels.
@@ -4967,12 +5119,59 @@ def get_add_port_channels_task_status(self, task_id):
49675119
This method constructs a message indicating the successful completion of the add port channels
49685120
operation. It then retrieves the task status using the provided task ID. If the operation is
49695121
successful, it fetches existing port channels and updates the message with the names of the
4970-
newly created port channels.
5122+
newly created port channels. Handles both single batch and sequential batch processing.
49715123
"""
49725124
task_name = "Add Port Channel(s) Task"
49735125
add_port_channels_params = self.want["add_port_channels_params"]
5126+
payload = add_port_channels_params.get("payload", [])
5127+
batch_size = self.params.get("sda_fabric_port_channel_limit", 20)
5128+
5129+
if len(payload) > batch_size:
5130+
self.log(
5131+
"Processing sequential add port channels task status for {0} port channels".format(
5132+
len(payload)
5133+
),
5134+
"INFO",
5135+
)
5136+
5137+
if self.status == "success":
5138+
# Fetch existing port channels to get the names
5139+
existing_port_channels = self.get_port_channels(
5140+
self.have.get("get_port_channels_params")
5141+
)
5142+
5143+
# Compare interface names and collect created port channel names
5144+
port_channels_names = []
5145+
for port_channel in existing_port_channels:
5146+
for payload_channel in payload:
5147+
if set(payload_channel["interfaceNames"]) == set(
5148+
port_channel["interfaceNames"]
5149+
):
5150+
port_channels_names.append(port_channel["portChannelName"])
5151+
break
5152+
5153+
self.log(
5154+
"Names of port_channels that were successfully created via sequential processing: {0}".format(
5155+
port_channels_names
5156+
),
5157+
"DEBUG",
5158+
)
5159+
5160+
updated_msg = {}
5161+
updated_msg[
5162+
"{0} Succeeded for following port channel(s) (Sequential Processing)".format(task_name)
5163+
] = {
5164+
"success_count": len(port_channels_names),
5165+
"success_port_channels": port_channels_names,
5166+
"total_batches": (len(payload) + batch_size - 1) // batch_size,
5167+
"sequential_processing": True,
5168+
}
5169+
self.msg = updated_msg
5170+
5171+
return self
5172+
49745173
msg = "{0} has completed successfully for params: {1}.".format(
4975-
task_name, add_port_channels_params["payload"]
5174+
task_name, payload
49765175
)
49775176

49785177
# Execute the task and get the status
@@ -4996,7 +5195,7 @@ def get_add_port_channels_task_status(self, task_id):
49965195
# Compare interface names and collect created port channel names
49975196
port_channels_names = []
49985197
for port_channel in existing_port_channels:
4999-
for payload_channel in add_port_channels_params["payload"]:
5198+
for payload_channel in payload:
50005199
if set(payload_channel["interfaceNames"]) == set(
50015200
port_channel["interfaceNames"]
50025201
):
@@ -5033,16 +5232,51 @@ def get_update_port_channels_task_status(self, task_id):
50335232
Description:
50345233
This method constructs a message indicating the successful completion of the update port channels
50355234
operation. It then retrieves the task status using the provided task ID and logs the relevant information.
5235+
Handles both single batch and sequential batch processing.
50365236
"""
50375237
task_name = "Update Port Channel(s) Task"
5038-
msg = {}
50395238

50405239
# Retrieve the parameters for updating port channels
50415240
update_port_channels_params = self.want.get("update_port_channels_params")
5241+
payload = update_port_channels_params.get("payload", [])
5242+
batch_size = self.params.get("sda_fabric_port_channel_limit", 20)
50425243
port_channels_list = [
50435244
port.get("portChannelName")
5044-
for port in update_port_channels_params["payload"]
5245+
for port in payload
50455246
]
5247+
5248+
# Check if this was sequential processing (more than batch_size port channels)
5249+
if len(payload) > batch_size:
5250+
# For sequential processing, the task status was already checked during processing
5251+
# We just need to prepare the final message
5252+
self.log(
5253+
"Processing sequential update port channels task status for {0} port channels".format(
5254+
len(payload)
5255+
),
5256+
"INFO",
5257+
)
5258+
5259+
if self.status == "success":
5260+
msg = {}
5261+
msg["{0} Succeeded for following port channel(s) (Sequential Processing)".format(task_name)] = {
5262+
"success_count": len(port_channels_list),
5263+
"success_port_channels": port_channels_list,
5264+
"total_batches": (len(payload) + batch_size - 1) // batch_size,
5265+
"sequential_processing": True,
5266+
}
5267+
self.msg = msg
5268+
return self.get_task_status_from_tasks_by_id(task_id, task_name, msg)
5269+
else:
5270+
msg = {}
5271+
msg["{0} Failed during sequential processing".format(task_name)] = {
5272+
"total_port_channels": len(port_channels_list),
5273+
"port_channels": port_channels_list,
5274+
"sequential_processing": True,
5275+
"status": self.status,
5276+
}
5277+
return self.get_task_status_from_tasks_by_id(task_id, task_name, msg)
5278+
5279+
msg = {}
50465280
msg["{0} Succeeded for following port channel(s)".format(task_name)] = {
50475281
"success_count": len(port_channels_list),
50485282
"success_port_channels": port_channels_list,
@@ -7000,6 +7234,7 @@ def main():
70007234
"dnac_log": {"type": "bool", "default": False},
70017235
"validate_response_schema": {"type": "bool", "default": True},
70027236
"config_verify": {"type": "bool", "default": False},
7237+
"sda_fabric_port_channel_limit": {"type": "int", "default": 20},
70037238
"dnac_api_task_timeout": {"type": "int", "default": 1200},
70047239
"dnac_task_poll_interval": {"type": "int", "default": 2},
70057240
"config": {"required": True, "type": "list", "elements": "dict"},

0 commit comments

Comments
 (0)