Commit 76c90902 authored by Pedro Duarte's avatar Pedro Duarte
Browse files

fix on the aggregation logic

parent 2440159e
Loading
Loading
Loading
Loading
+30 −38
Original line number Diff line number Diff line
@@ -101,12 +101,14 @@ class GnmiSessionHandler:
                    if resource_type not in grouped_updates:
                        grouped_updates[resource_type] = []
                    grouped_updates[resource_type].append(update)
                    self._logger.info('Grouped update path %s under resource type %s', path_str, resource_type)
        
        self._logger.debug('Grouped updates by resource type: %s', {k: len(v) for k, v in grouped_updates.items()})

        # Create aggregated notifications
        aggregated_notifications = []
        for resource_type, updates in grouped_updates.items():
            if len(updates) > 1:
                # Create a new notification with all updates for this resource type
            # Always create a new notification, regardless of the number of updates
            aggregated_notification = type(notifications[0])()
            # Copy the first notification's structure
            aggregated_notification.CopyFrom(notifications[0])
@@ -117,11 +119,9 @@ class GnmiSessionHandler:
            if hasattr(updates[0], 'timestamp') and updates[0].timestamp:
                aggregated_notification.timestamp = max(u.timestamp for u in updates if u.timestamp)
            aggregated_notifications.append(aggregated_notification)
                self._logger.debug('Aggregated %d updates for resource type: %s', len(updates), resource_type)
            else:
                aggregated_notifications.append(notifications[0]) 
            self._logger.info('Aggregated %d updates for resource type: %s', len(updates), resource_type)

        self._logger.debug('Aggregated %d field responses into %d resource-level notifications', 
        self._logger.info('Aggregated %d field responses into %d resource-level notifications', 
                         len(notifications), len(aggregated_notifications))

        return aggregated_notifications
@@ -129,7 +129,8 @@ class GnmiSessionHandler:
    def _find_common_resource_path(self, updates):
        """
        Finds the common resource path among a list of updates.
        This is a heuristic and might not be accurate for all models.
        For Stratum compatibility, we always return the top-level resource path
        (e.g., /interfaces, /components) since that's what the handlers expect.
        """
        if not updates:
            return None
@@ -140,26 +141,15 @@ class GnmiSessionHandler:
        
        self._logger.debug('Finding common path. First path: %s, parts: %s', first_path_str, first_path_parts)

        # Iterate through the rest of the updates to find common segments
        for update in updates[1:]:
            update_path_str = path_to_string(update.path)
            update_path_parts = update_path_str.strip('/').split('/')
            
            self._logger.debug('Comparing with path: %s, parts: %s', update_path_str, update_path_parts)

            # Find the minimum length of the two paths
            min_len = min(len(first_path_parts), len(update_path_parts))

            # Compare segments up to the minimum length
            for i in range(min_len):
                if first_path_parts[i] != update_path_parts[i]:
                    # Return the common path up to the point of divergence
                    common_path = '/'.join(first_path_parts[:i])
                    self._logger.debug('Found common path: %s (diverged at index %d)', common_path, i)
                    return common_path
        # For Stratum compatibility, always return the top-level resource path
        # This ensures we get paths like /interfaces, /components that match PATH_TO_HANDLER
        if len(first_path_parts) >= 1:
            top_level_path = '/' + first_path_parts[0]
            self._logger.debug('Returning top-level resource path: %s', top_level_path)
            return top_level_path
        
        # If all updates have the same path, return the full path
        self._logger.debug('All paths are identical, returning: %s', first_path_str)
        # Fallback: return the original path if we can't extract top-level
        self._logger.debug('Could not extract top-level path, returning original: %s', first_path_str)
        return first_path_str

    def _reconstruct_object_from_updates(self, updates):
@@ -305,10 +295,12 @@ class GnmiSessionHandler:
                if common_path:
                    self._logger.debug('Processing notification for resource: %s with %d updates', 
                                     common_path, len(notification.update))
                    self._logger.debug('Common path: %s', common_path)
                    try:
                        # Reconstruct the complete object from all updates
                        reconstructed_data = self._reconstruct_object_from_updates(notification.update)
                        self._logger.debug('Reconstructed data keys: %s', list(reconstructed_data.keys()))
                        self._logger.debug('Calling parse with path: %s and data: %s', common_path, reconstructed_data)
                        # Parse the reconstructed object at the resource level
                        results.extend(parse(common_path, reconstructed_data, self._yang_handler))
                    except Exception as e: