Skip to content

Conversation

@Priyadharshini16092002
Copy link

@Priyadharshini16092002 Priyadharshini16092002 commented Nov 10, 2025

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update

Description

The update includes fixes for 2 identified bugs in the fabric_devices_info module.

Bug Fix:

  1. [fabric_device_info]: Missing information returned for port channels
  2. [fabric_info]: The excessive and highly redundant output hinders the efficient collection of device information (requested_info: handoff_info)

Root Cause (if applicable):

  1. Expected port channel details to be retrieved for onboarding info, currently only port assignment details are being retrieved.
  2. The handoff_info retrieval process included repetitive entries due to redundant looping.

Fix Implemented: [Describe the fix applied]

  1. Added port_channel details to be retrieved for onboarding info
  2. Changed the logic to eliminate redundant data.

Enhancement: [Brief description of the improvement/enhancement made]
Enhancement Description: [Explain what was enhanced, why, and how]
Impact Area: [Mention which part of the system/codebase is affected]

Testing Done:

  • Manual testing
  • Unit tests
  • Integration tests

Test cases covered: [Mention test case IDs or brief points]

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • All the sanity checks have been completed and the sanity test cases have been executed

Ansible Best Practices

  • Tasks are idempotent (can be run multiple times without changing state)
  • Variables and secrets are handled securely (e.g., using ansible-vault or environment variables)
  • Playbooks are modular and reusable
  • Handlers are used for actions that need to run on change

Documentation

  • All options and parameters are documented clearly.
  • Examples are provided and tested.
  • Notes and limitations are clearly stated.

Screenshots (if applicable)

Notes to Reviewers

self.log("Retrieving fabric device onboarding information for lifecycle management and troubleshooting", "INFO")
self.log("Processing port channel details for {0} fabric devices across fabric sites".format(len(filtered_fabric_devices)), "DEBUG")

device_identifier = self.want["fabric_devices"][0].get("device_identifier")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.log(
    "Port channel retrieval configuration - device_identifier specified: {0}".format(
        bool(device_identifier)
    ),
    "DEBUG"
)

all_port_channel_info_list = []

# Statistics tracking for port channel operations
statistics = {
    'devices_processed': 0,
    'devices_with_port_channels': 0,
    'devices_without_port_channels': 0,
    'devices_with_errors': 0,
    'total_port_channels_retrieved': 0,
    'total_api_calls': 0
}

self.log(
    "Beginning port channel data collection across {0} fabric devices".format(
        len(filtered_fabric_devices)
    ),
    "INFO"
)

devices_without_port_channels_data = 0
devices_with_errors = 0

for index, (ip, fabric_id) in enumerate(filtered_fabric_devices.items()):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    self.log(
        "Processing outer loop for device {0}/{1} - "
        "IP: {2}, Fabric ID: {3}".format(
            index, len(filtered_fabric_devices), device_ip, fabric_id
        ),
        "DEBUG"
    )

devices_with_errors = 0

for index, (ip, fabric_id) in enumerate(filtered_fabric_devices.items()):
ip_device_uuid_map = self.get_device_ids_from_device_ips([ip])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

    if not ip_device_uuid_map or device_ip not in ip_device_uuid_map:
        self.log(
            "Failed to retrieve device UUID for IP {0} - skipping port channel retrieval".format(
                device_ip
            ),
            "WARNING"
        )
        statistics['devices_with_errors'] += 1
        all_port_channel_info_list.append({
            "device_ip": device_ip,
            "port_channel_details": "Error: Unable to retrieve device UUID"
        })
        continue
    
    # Inner loop processing each device IP and UUID mapping
    for ip, device_uuid in ip_device_uuid_map.items():

for index, (ip, fabric_id) in enumerate(filtered_fabric_devices.items()):
ip_device_uuid_map = self.get_device_ids_from_device_ips([ip])
for ip, device_uuid in ip_device_uuid_map.items():
devices_processed += 1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

        statistics['devices_processed'] += 1
        
        self.log(
            "Processing inner loop for device {0} - UUID: {1}".format(
                ip, device_uuid
            ),
            "DEBUG"
        )
        
        self.log(
            "Initiating port channel data retrieval for fabric device {0}".format(ip),
            "DEBUG"
        )

self.log(
"Added 'network_device_id' parameter for device {0}: {1}".format(ip, device_uuid),
"DEBUG"
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

            statistics['total_api_calls'] += 1

family="sda",
function="get_port_channels",
params=params
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

            # Validate API response structure
            if not response or not isinstance(response, dict):
                self.log(
                    "Invalid API response structure for device {0} - "
                    "expected dict, got: {1}".format(
                        ip, type(response).__name__
                    ),
                    "WARNING"
                )
                statistics['devices_with_errors'] += 1
                all_port_channel_info_list.append({
                    "device_ip": ip,
                    "port_channel_details": "Error: Invalid API response structure"
                })
                continue
            
            port_channel_data = response.get("response", [])
            
            if not isinstance(port_channel_data, list):
                self.log(
                    "Unexpected response data type for device {0} - "
                    "expected list, got: {1}".format(
                        ip, type(port_channel_data).__name__
                    ),
                    "WARNING"
                )
                statistics['devices_with_errors'] += 1
                all_port_channel_info_list.append({
                    "device_ip": ip,
                    "port_channel_details": "Error: Unexpected response data format"
                })
                continue

),
"DEBUG"
)
if onboarding_data:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

           if port_channel_data:
                statistics['devices_with_port_channels'] += 1
                statistics['total_port_channels_retrieved'] += len(port_channel_data)
                
                self.log(
                    "Port channel configuration found for fabric device {0} - "
                    "retrieved {1} port channel records".format(
                        ip, len(port_channel_data)
                    ),
                    "INFO"
                )
                
                all_port_channel_info_list.append({
                    "device_ip": ip,
                    "port_channel_details": port_channel_data
                })
                
                for idx, port_channel in enumerate(port_channel_data, start=1):
                    port_channel_id = port_channel.get("id", "Unknown")
                    interface_name = port_channel.get("interfaceName", "Unknown")
                    
                    self.log(
                        "Port channel {0}/{1} details for device {2} - "
                        "ID: {3}, Interface: {4}".format(
                            idx, len(port_channel_data), ip, 
                            port_channel_id, interface_name
                        ),
                        "DEBUG"
                    )
                
            else:
                statistics['devices_without_port_channels'] += 1
                
                self.log(
                    "No port channel configuration found for fabric device {0} - "
                    "device may not have configured port channels".format(ip),
                    "DEBUG"
                )
                
                all_port_channel_info_list.append({
                    "device_ip": ip,
                    "port_channel_details": []
                })

all_onboarding_info_list.append({
"device_ip": ip,
"port_channel_details": "Error: {0}".format(api_err)
})
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

continue

"port_channel_details": "Error: {0}".format(api_err)
})

result = [{"port_channel_info": all_onboarding_info_list}]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result = [{"port_channel_info": all_port_channel_info_list}]

self.log(
    "Port channel configuration retrieval completed - "
    "devices processed: {0}, with port channels: {1}, "
    "without port channels: {2}, with errors: {3}".format(
        statistics['devices_processed'],
        statistics['devices_with_port_channels'],
        statistics['devices_without_port_channels'],
        statistics['devices_with_errors']
    ),
    "INFO"
)

self.log(
    "Port channel retrieval statistics - "
    "total API calls: {0}, total port channels retrieved: {1}".format(
        statistics['total_api_calls'],
        statistics['total_port_channels_retrieved']
    ),
    "INFO"
)

if statistics['devices_with_port_channels'] > 0:
    self.log(
        "Fabric devices with port channel configurations indicating "
        "successful interface aggregation: {0}".format(
            statistics['devices_with_port_channels']
        ),
        "INFO"
    )

if statistics['devices_without_port_channels'] > 0:
    self.log(
        "Fabric devices without port channel configurations: {0}".format(
            statistics['devices_without_port_channels']
        ),
        "INFO"
    )

if statistics['devices_with_errors'] > 0:
    self.log(
        "Warning: {0} devices encountered errors during port channel "
        "configuration retrieval - check individual device logs for details".format(
            statistics['devices_with_errors']
        ),
        "WARNING"
    )

successful_devices = [
    entry["device_ip"] for entry in all_port_channel_info_list 
    if isinstance(entry["port_channel_details"], list) and entry["port_channel_details"]
]

if successful_devices:
    self.log(
        "Successfully retrieved port channel configurations for devices: {0}".format(
            successful_devices
        ),
        "DEBUG"
    )

self.log(
    "Port channel configuration retrieval operation completed for {0} "
    "fabric devices with {1} total device entries processed".format(
        len(filtered_fabric_devices), len(all_port_channel_info_list)
    ),
    "INFO"
)

self.log(
    "Final aggregated port channel information result: {0}".format(result),
    "DEBUG"
)

return result

@madhansansel madhansansel merged commit 57ce499 into cisco-en-programmability:main Nov 11, 2025
12 of 14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants