From 33fbfebd380879470a342da4061e3e8f6820addb Mon Sep 17 00:00:00 2001 From: gifrerenom <lluis.gifre@cttc.es> Date: Fri, 8 Nov 2024 11:26:56 +0000 Subject: [PATCH] Service component - L3NM gNMI OpenConfig: - StaticRouteGenerator: Fixed link endpoints compuotation - ConfigRuleComposer: Reverted to default network instance as cEOS does not work properly with VRFs - ConfigRuleComposer: Added interface deactivation - Improved logging - Updated unitary tests --- .../ConfigRuleComposer.py | 32 +++++++++++++---- .../L3NMGnmiOpenConfigServiceHandler.py | 9 ++--- .../StaticRouteGenerator.py | 12 +++++-- .../MockServiceHandler.py | 36 +++++++++++++++++-- .../test_unitary_sns4sns.py | 20 +++++------ 5 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py index c8227975f..54101d041 100644 --- a/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py +++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/ConfigRuleComposer.py @@ -21,7 +21,8 @@ from service.service.service_handler_api.AnyTreeTools import TreeNode LOGGER = logging.getLogger(__name__) -NETWORK_INSTANCE = 'teraflowsdn' +#NETWORK_INSTANCE = 'teraflowsdn' +NETWORK_INSTANCE = 'default' RE_IF = re.compile(r'^\/interface\[([^\]]+)\]$') RE_SUBIF = re.compile(r'^\/interface\[([^\]]+)\]\/subinterface\[([^\]]+)\]$') @@ -109,11 +110,18 @@ class EndpointComposer: if self.ipv4_prefix_len is None: return [] json_config_rule = json_config_rule_delete if delete else json_config_rule_set config_rules = [ - json_config_rule(*_network_instance_interface( - network_instance_name, self.objekt.name, self.sub_interface_index - )), + #json_config_rule(*_network_instance_interface( + # network_instance_name, self.objekt.name, self.sub_interface_index + #)), ] - if not delete: + if delete: + config_rules.extend([ + json_config_rule(*_interface( + self.objekt.name, index=self.sub_interface_index, address_ip=None, + address_prefix=None, enabled=False + )), + ]) + else: config_rules.extend([ json_config_rule(*_interface( self.objekt.name, index=self.sub_interface_index, address_ip=self.ipv4_address, @@ -128,6 +136,12 @@ class EndpointComposer: 'address_ip' : self.ipv4_address, 'address_prefix': self.ipv4_prefix_len, } + + def __str__(self): + data = {'uuid': self.uuid} + if self.objekt is not None: data['name'] = self.objekt.name + data.update(self.dump()) + return json.dumps(data) class DeviceComposer: def __init__(self, device_uuid : str) -> None: @@ -212,7 +226,7 @@ class DeviceComposer: json_config_rule = json_config_rule_delete if delete else json_config_rule_set config_rules = [ - json_config_rule(*_network_instance(network_instance_name, 'L3VRF')) + #json_config_rule(*_network_instance(network_instance_name, 'L3VRF')) ] for endpoint in self.endpoints.values(): config_rules.extend(endpoint.get_config_rules(network_instance_name, delete=delete)) @@ -240,6 +254,12 @@ class DeviceComposer: 'static_routes' : self.static_routes, } + def __str__(self): + data = {'uuid': self.uuid} + if self.objekt is not None: data['name'] = self.objekt.name + data.update(self.dump()) + return json.dumps(data) + class ConfigRuleComposer: def __init__(self) -> None: self.objekt : Optional[Service] = None diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py index 8aa3781a4..4099675fa 100644 --- a/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py +++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/L3NMGnmiOpenConfigServiceHandler.py @@ -65,8 +65,9 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler): self.__endpoint_map[(device_uuid, endpoint_uuid)] = (device_obj.name, endpoint_obj.name) + LOGGER.debug('[pre] config_rule_composer = {:s}'.format(json.dumps(self.__config_rule_composer.dump()))) self.__static_route_generator.compose(endpoints) - LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self.__config_rule_composer.dump()))) + LOGGER.debug('[post] config_rule_composer = {:s}'.format(json.dumps(self.__config_rule_composer.dump()))) def _do_configurations( self, config_rules_per_device : Dict[str, List[Dict]], endpoints : List[Tuple[str, str, Optional[str]]], @@ -110,8 +111,8 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler): #network_instance_name = service_uuid.split('-')[0] #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=False) config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=False) - LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device))) - results = self._do_configurations(config_rules_per_device, endpoints) + LOGGER.debug('config_rules_per_device={:s}'.format(json.dumps(config_rules_per_device))) + results = self._do_configurations(config_rules_per_device, endpoints, delete=False) LOGGER.debug('results={:s}'.format(str(results))) return results @@ -128,7 +129,7 @@ class L3NMGnmiOpenConfigServiceHandler(_ServiceHandler): #network_instance_name = service_uuid.split('-')[0] #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=True) config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=True) - LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device))) + LOGGER.debug('config_rules_per_device={:s}'.format(json.dumps(config_rules_per_device))) results = self._do_configurations(config_rules_per_device, endpoints, delete=True) LOGGER.debug('results={:s}'.format(str(results))) return results diff --git a/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py b/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py index 201f22e63..c52321473 100644 --- a/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py +++ b/src/service/service/service_handlers/l3nm_gnmi_openconfig/StaticRouteGenerator.py @@ -63,12 +63,20 @@ class StaticRouteGenerator: def _compute_link_endpoints( self, connection_hop_list : List[Tuple[str, str, Optional[str]]] ) -> List[Tuple[Tuple[str, str, Optional[str]], Tuple[str, str, Optional[str]]]]: + # In some cases connection_hop_list might contain repeated endpoints, remove them here. + added_connection_hops = set() + filtered_connection_hop_list = list() + for connection_hop in connection_hop_list: + if connection_hop in added_connection_hops: continue + filtered_connection_hop_list.append(connection_hop) + added_connection_hops.add(connection_hop) + connection_hop_list = filtered_connection_hop_list + num_connection_hops = len(connection_hop_list) if num_connection_hops % 2 != 0: raise Exception('Number of connection hops must be even') if num_connection_hops < 4: raise Exception('Number of connection hops must be >= 4') - # Skip service endpoints (first and last) - it_connection_hops = iter(connection_hop_list[1:-1]) + it_connection_hops = iter(connection_hop_list) return list(zip(it_connection_hops, it_connection_hops)) def _compute_link_addresses( diff --git a/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py index 22da218ab..a480f6b31 100644 --- a/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py +++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/MockServiceHandler.py @@ -19,6 +19,7 @@ from common.tools.object_factory.Connection import json_connection_id from common.tools.object_factory.Device import json_device_id from common.type_checkers.Checkers import chk_type from service.service.service_handler_api._ServiceHandler import _ServiceHandler +#from service.service.service_handler_api.AnyTreeTools import TreeNode from service.service.service_handler_api.SettingsHandler import SettingsHandler from service.service.service_handler_api.Tools import get_device_endpoint_uuids, get_endpoint_matching from .MockTaskExecutor import MockTaskExecutor @@ -45,6 +46,10 @@ class MockServiceHandler(_ServiceHandler): service_settings = self.__settings_handler.get_service_settings() self.__config_rule_composer.configure(self.__service, service_settings) + #prev_endpoint_obj = None + #prev_endpoint = None + #settings_for_next = None + #for i,endpoint in enumerate(endpoints): for endpoint in endpoints: device_uuid, endpoint_uuid = get_device_endpoint_uuids(endpoint) @@ -60,8 +65,35 @@ class MockServiceHandler(_ServiceHandler): _endpoint = _device.get_endpoint(endpoint_obj.name) _endpoint.configure(endpoint_obj, endpoint_settings) + #if settings_for_next is not None: + # _endpoint.configure(endpoint_obj, settings_for_next) + # settings_for_next = None + + #if endpoint_settings is not None and 'neighbor_address' in endpoint_settings.value: + # _neighbor_settings = {'address_ip': endpoint_settings.value['neighbor_address']} + # + # if 'address_prefix' in endpoint_settings.value: + # _neighbor_settings['address_prefix'] = endpoint_settings.value['address_prefix'] + # elif 'prefix_length' in endpoint_settings.value: + # _neighbor_settings['address_prefix'] = endpoint_settings.value['prefix_length'] + # else: + # MSG = 'IP Address Prefix not found. Tried: address_prefix and prefix_length. endpoint_settings.value={:s}' + # raise Exception(MSG.format(str(endpoint_settings.value))) + # + # neighbor_settings = TreeNode('.') + # neighbor_settings.value = _neighbor_settings + # if i % 2 == 0: + # # configure in next endpoint + # settings_for_next = neighbor_settings + # else: + # # configure in previous endpoint + # prev_endpoint.configure(prev_endpoint_obj, neighbor_settings) + self.__endpoint_map[(device_uuid, endpoint_uuid)] = (device_obj.name, endpoint_obj.name) + #prev_endpoint = _endpoint + #prev_endpoint_obj = endpoint_obj + self.__static_route_generator.compose(endpoints) LOGGER.debug('config_rule_composer = {:s}'.format(json.dumps(self.__config_rule_composer.dump()))) @@ -106,7 +138,7 @@ class MockServiceHandler(_ServiceHandler): #network_instance_name = service_uuid.split('-')[0] #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=False) config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=False) - LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device))) + LOGGER.debug('config_rules_per_device={:s}'.format(json.dumps(config_rules_per_device))) results = self._do_configurations(config_rules_per_device, endpoints) LOGGER.debug('results={:s}'.format(str(results))) return results @@ -123,7 +155,7 @@ class MockServiceHandler(_ServiceHandler): #network_instance_name = service_uuid.split('-')[0] #config_rules_per_device = self.__config_rule_composer.get_config_rules(network_instance_name, delete=True) config_rules_per_device = self.__config_rule_composer.get_config_rules(delete=True) - LOGGER.debug('config_rules_per_device={:s}'.format(str(config_rules_per_device))) + LOGGER.debug('config_rules_per_device={:s}'.format(json.dumps(config_rules_per_device))) results = self._do_configurations(config_rules_per_device, endpoints, delete=True) LOGGER.debug('results={:s}'.format(str(results))) return results diff --git a/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary_sns4sns.py b/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary_sns4sns.py index 0177500e2..64035f1bb 100644 --- a/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary_sns4sns.py +++ b/src/service/tests/test_l3nm_gnmi_static_rule_gen/test_unitary_sns4sns.py @@ -37,27 +37,23 @@ SERVICE = Service(**json_service_l3nm_planned( json_endpoint_id(json_device_id('edge-net'), 'eth1'), ], config_rules=[ + json_config_rule_set('/settings', {'address_families': ['IPV4'], 'mtu': 1500}), + json_config_rule_set('/static_routing', {}), + json_config_rule_set('/device[core-net]/endpoint[eth1]/settings', { - 'address_ip': '10.10.10.0', 'address_prefix': 24, 'index': 0 - }), - json_config_rule_set('/device[r1]/endpoint[eth10]/settings', { - 'address_ip': '10.10.10.229', 'address_prefix': 24, 'index': 0 - }), - json_config_rule_set('/device[r2]/endpoint[eth10]/settings', { - 'address_ip': '10.158.72.229', 'address_prefix': 24, 'index': 0 + 'address_ip': '10.10.10.0', 'neighbor_address': '10.10.10.229', 'address_prefix': 24, 'index': 0 }), json_config_rule_set('/device[edge-net]/endpoint[eth1]/settings', { - 'address_ip': '10.158.72.0', 'address_prefix': 24, 'index': 0 + 'address_ip': '10.158.72.0', 'neighbor_address': '10.158.72.229', 'address_prefix': 24, 'index': 0 }), ] )) CONNECTION_ENDPOINTS : List[Tuple[str, str, Optional[str]]] = [ #('core-net', 'int', None), - ('core-net', 'eth1', None), - ('r1', 'eth10', None), ('r1', 'eth2', None), - ('r2', 'eth1', None), ('r2', 'eth10', None), - ('edge-net', 'eth1', None), + ('core-net', 'eth1', None), ('r1', 'eth10', None), + ('r1', 'eth2', None), ('r2', 'eth1', None), + ('r2', 'eth10', None), ('edge-net', 'eth1', None), #('edge-net', 'int', None), ] -- GitLab