Commit 33fbfebd authored by Lluis Gifre Renom's avatar Lluis Gifre Renom
Browse files

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
parent 2d23b59d
Loading
Loading
Loading
Loading
+26 −6
Original line number Diff line number Diff line
@@ -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,
@@ -129,6 +137,12 @@ class EndpointComposer:
            '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:
        self.uuid = device_uuid
@@ -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
+5 −4
Original line number Diff line number Diff line
@@ -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
+10 −2
Original line number Diff line number Diff line
@@ -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(
+34 −2
Original line number Diff line number Diff line
@@ -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
+8 −12
Original line number Diff line number Diff line
@@ -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),
]