Commit 0cf04875 authored by Pablo Armingol's avatar Pablo Armingol
Browse files

1) Multivendor support in L3VPN(steps 1,2 and 3)

2) Support to choose between "Jinja" and "pyangbind".
3) WebUI modification for creating services
4) Changes in ConfigRules multivendor to adapt to new features
parent 48658bbb
Loading
Loading
Loading
Loading
+25 −17
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ class NetconfSessionHandler:
        self.__username         = settings.get('username')
        self.__password         = settings.get('password')
        self.__vendor           = settings.get('vendor')
        self.__version           = settings.get('version', "1")
        self.__key_filename     = settings.get('key_filename')
        self.__hostkey_verify   = settings.get('hostkey_verify', True)
        self.__look_for_keys    = settings.get('look_for_keys', True)
@@ -70,6 +71,7 @@ class NetconfSessionHandler:
        self.__device_params    = settings.get('device_params', {})
        self.__manager_params   = settings.get('manager_params', {})
        self.__nc_params        = settings.get('nc_params', {})
        self.__message_renderer = settings.get('message_renderer','jinja')
        self.__manager : Manager   = None
        self.__candidate_supported = False

@@ -97,6 +99,12 @@ class NetconfSessionHandler:
    @property
    def vendor(self): return self.__vendor
    
    @property
    def version(self): return self.__version
    
    @property
    def message_renderer(self): return self.__message_renderer

    @RETRY_DECORATOR
    def get(self, filter=None, with_defaults=None): # pylint: disable=redefined-builtin
        with self.__lock:
@@ -196,22 +204,22 @@ def edit_config(
    format='xml' # pylint: disable=redefined-builtin
):
    str_method = 'DeleteConfig' if delete else 'SetConfig'
    #logger.debug('[{:s}] resources = {:s}'.format(str_method, str(resources)))
    logger.debug('[{:s}] resources = {:s}'.format(str_method, str(resources)))
    results = [None for _ in resources]
    for i,resource in enumerate(resources):
        str_resource_name = 'resources[#{:d}]'.format(i)
        try:
            # logger.debug('[{:s}] resource = {:s}'.format(str_method, str(resource)))
            logger.debug('[{:s}] resource = {:s}'.format(str_method, str(resource)))
            chk_type(str_resource_name, resource, (list, tuple))
            chk_length(str_resource_name, resource, min_length=2, max_length=2)
            resource_key,resource_value = resource
            chk_string(str_resource_name + '.key', resource_key, allow_empty=False)
            str_config_messages = compose_config(                                                                          # get template for configuration
                resource_key, resource_value, delete=delete, vendor=netconf_handler.vendor)
                resource_key, resource_value, delete=delete, vendor=netconf_handler.vendor, message_renderer=netconf_handler.message_renderer)
            for str_config_message in str_config_messages:                                                                 # configuration of the received templates 
                if str_config_message is None: raise UnsupportedResourceKeyException(resource_key)
                # logger.debug('[{:s}] str_config_message[{:d}] = {:s}'.format(
                #    str_method, len(str_config_message), str(str_config_message)))
                logger.debug('[{:s}] str_config_message[{:d}] = {:s}'.format(
                   str_method, len(str_config_message), str(str_config_message)))
                netconf_handler.edit_config(                                                                               # configure the device
                    config=str_config_message, target=target, default_operation=default_operation,
                    test_option=test_option, error_option=error_option, format=format)
+2 −2
Original line number Diff line number Diff line
@@ -42,13 +42,13 @@ def generate_templates(resource_key: str, resource_value: str, delete: bool,vend
        elif "inter_instance_policies" in resource_key:
            result_templates.append(associate_RP_to_NI(data))
        elif "protocols" in resource_key:
            result_templates.append(add_protocol_NI(data))
            if vendor == "ADVA": result_templates.append(add_protocol_NI(data))
        elif "table_connections" in resource_key:
            result_templates.append(create_table_conns(data))
        elif "interface" in resource_key:
            result_templates.append(associate_If_to_NI(data))
        else:
            result_templates.append(create_network_instance(data))
            result_templates.append(create_network_instance(data,vendor))

    elif "interface" in list_resource_key[1]:                                           # interface rules management
        data: Dict[str, Any] = json.loads(resource_value)
+8 −7
Original line number Diff line number Diff line
from .openconfig_network_instance import openconfig_network_instance
from pyangbind.lib.serialise     import pybindIETFXMLEncoder

def create_network_instance(parameters):                   #[L2/L3] Creates a Network Instance as described in: /network_instance[{:s}] 
def create_network_instance(parameters,vendor):                   #[L2/L3] Creates a Network Instance as described in: /network_instance[{:s}] 
    NetInstance_name        = parameters['name']           #Retrieves the Name parameter of the NetInstance
    DEL                     = parameters['DEL']            #If the parameter DEL is set to "TRUE" that will mean that is for making a DELETE, ELSE is for creating
    verify = str(parameters)                               #Verify transforms the received parameters into a string format for later making verifications and modifications
@@ -27,7 +27,7 @@ def create_network_instance(parameters): #[L2/L3] Creates a Ne
        #Access the entry container
        NetInstance_set = Network_Instance.network_instances.network_instance.add(name = NetInstance_name)      
        NetInstance_set.config.name = NetInstance_name                                                          
        NetInstance_set.config.type = NetInstance_type 
        if vendor == 'ADVA': NetInstance_set.config.type = NetInstance_type 
        NetInstance_encapsulation = NetInstance_set.encapsulation.config

        #If the description parameter is defined [OPTIONAL-PARAMETER]
@@ -59,11 +59,12 @@ def create_network_instance(parameters): #[L2/L3] Creates a Ne
            NetInstance_set.config.route_distinguisher                            = NetInstance_Route_disting
            
            #If the router-id parameter is defined [OPTIONAL-PARAMETER]
            if verify.find('router_id')>0:
                NetInstance_Router_ID = parameters['router_id']    
                if  len(NetInstance_Router_ID) != 0: NetInstance_set.config.router_id = NetInstance_Router_ID     #If router-id parameter has a value
            #if verify.find('router_id')>0:
                #NetInstance_Router_ID = parameters['router_id']    
                #if  len(NetInstance_Router_ID) != 0: NetInstance_set.config.router_id = NetInstance_Router_ID     #If router-id parameter has a value

            #Encapsulation
            if vendor == 'ADVA':
                NetInstance_encapsulation.encapsulation_type = "MPLS"
                NetInstance_encapsulation.label_allocation_mode = "INSTANCE_LABEL"    
            #Dump the entire instance as RFC 750 XML
+26 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ import json, logging, lxml.etree as ET, re
from typing import Any, Dict, Optional
from jinja2 import Environment, PackageLoader, select_autoescape
from .Tools import generate_templates
from .ACL.ACL_multivendor              import acl_mgmt        
from device.service.driver_api._Driver import (
    RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL)
from .EndPoints import parse as parse_endpoints
@@ -23,6 +24,7 @@ from .Interfaces import parse as parse_interfaces, parse_counters
from .NetworkInstances import parse as parse_network_instances
from .RoutingPolicy import parse as parse_routing_policy
from .Acl import parse as parse_acl
LOGGER = logging.getLogger(__name__)

ALL_RESOURCE_KEYS = [
    RESOURCE_ENDPOINTS,
@@ -79,10 +81,28 @@ def parse(resource_key : str, xml_data : ET.Element):
    return parser(xml_data)

def compose_config( # template generation
    resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None
    resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None, message_renderer = str
) -> str:

    if (message_renderer == "pyangbind"):
        templates = (generate_templates(resource_key, resource_value, delete,vendor))
        return [
            '<config>{:s}</config>'.format(template) # format correction
            for template in templates
            ]

    elif (message_renderer == "jinja"):
        template_name = '{:s}/edit_config.xml'.format(RE_REMOVE_FILTERS.sub('', resource_key))
        template = JINJA_ENV.get_template(template_name)

        if "acl_ruleset" in resource_key:                                               # MANAGING ACLs
            template.extend(acl_mgmt(resource_value,vendor))                            # MANAGING ACLs
        data : Dict[str, Any] = json.loads(resource_value)
        operation = 'delete' if delete else 'merge'
        LOGGER.info('Template={:s}'.format('<config>{:s}</config>'.format(template.render(**data, operation=operation, vendor=vendor).strip()))) 

        return ['<config>{:s}</config>'.format(template.render(**data, operation=operation, vendor=vendor).strip())]
    
    else:
        raise ValueError('Invalid message_renderer value: {}'.format(message_renderer)) 
    
 No newline at end of file
+3 −3
Original line number Diff line number Diff line
@@ -255,8 +255,8 @@ class RequestGenerator:
                json_constraint_sla_latency(e2e_latency_ms),
            ]

            vlan_id = num_request % 1000
            circuit_id = '{:03d}'.format(vlan_id + 100)
            vlan_id = 300 + (num_request % 1000)
            circuit_id = '{:03d}'.format(vlan_id)

            src_device_name = self._device_data[src_device_uuid]['name']
            src_endpoint_name = self._device_endpoint_data[src_device_uuid][src_endpoint_uuid]['name']
@@ -306,7 +306,7 @@ class RequestGenerator:

            bgp_as = 65000 + (num_request % 10000)

            vlan_id = num_request % 100 +100
            vlan_id = num_request % 1000 +300
            x = num_request % 255
            y = num_request % 25 * num_request % 10
            route_distinguisher = '{:5d}:{:03d}'.format(bgp_as, vlan_id)
Loading