diff --git a/common_requirements.in b/common_requirements.in index 12c6c778d107ebf27ad53a25b2da60ad2f65286e..38812dbf0d927293bd1c7996b685f4ec060c5438 100644 --- a/common_requirements.in +++ b/common_requirements.in @@ -25,3 +25,4 @@ pytest==6.2.5 pytest-benchmark==3.4.1 python-dateutil==2.8.2 pytest-depends==1.0.1 +PyYAML>=6.0 diff --git a/src/device/Dockerfile b/src/device/Dockerfile index d8541912838a4e7c19923a6ad10c67d909a4a622..7ab74c2b4ceff3acfc479b96e7a834e4ce2a8037 100644 --- a/src/device/Dockerfile +++ b/src/device/Dockerfile @@ -55,6 +55,10 @@ RUN pip-compile --quiet --output-file=common_requirements.txt common_requirement RUN python3 -m pip install -r common_requirements.txt # Add common files into working directory +WORKDIR /var/teraflow/inter_device_translation +COPY src/inter_device_translation/. ./ + +# Add device translation files into working directory WORKDIR /var/teraflow/common COPY src/common/. ./ RUN rm -rf proto diff --git a/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py b/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py index 6eb9271ab436c5ee85dae39795b346406916eee4..9ab3ff53af849e840de31bd8c9b15fec67e902d6 100644 --- a/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py +++ b/src/device/service/drivers/gnmi_openconfig/GnmiSessionHandler.py @@ -38,6 +38,7 @@ class GnmiSessionHandler: self._username = settings.get('username') self._password = settings.get('password') self._use_tls = settings.get('use_tls', False) + self._vendor = settings.get('vendor') self._channel : Optional[grpc.Channel] = None self._stub : Optional[gNMIStub] = None self._monit_thread = None @@ -63,6 +64,10 @@ class GnmiSessionHandler: @property def out_samples(self): return self._out_samples + + @property + def device_type(self): + return self._vendor.lower() if self._vendor else 'oc' def connect(self): with self._lock: @@ -97,7 +102,7 @@ class GnmiSessionHandler: try: chk_string(str_resource_name, resource_key, allow_empty=False) self._logger.debug('[GnmiSessionHandler:get] resource_key = {:s}'.format(str(resource_key))) - str_path = get_path(resource_key) + str_path = get_path(resource_key, self.device_type) self._logger.debug('[GnmiSessionHandler:get] str_path = {:s}'.format(str(str_path))) get_request.path.append(path_from_string(str_path)) except Exception as e: # pylint: disable=broad-except @@ -141,7 +146,7 @@ class GnmiSessionHandler: value = decode_value(update.val) #resource_key_tuple[1] = value #resource_key_tuple[2] = True - results.extend(parse(str_path, value, self._yang_handler)) + results.extend(parse(str_path, value, self._yang_handler, self.device_type)) except Exception as e: # pylint: disable=broad-except MSG = 'Exception processing update {:s}' self._logger.exception(MSG.format(grpc_message_to_json_string(update))) @@ -178,7 +183,7 @@ class GnmiSessionHandler: #if resource_tuple is None: continue #_, value, exists, operation_done = resource_tuple if isinstance(resource_value, str): resource_value = json.loads(resource_value) - str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=False) + str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=False, device_type=self.device_type) if str_path is None: continue # nothing to set #self._logger.info('---3') #self._logger.info(str(str_path)) @@ -252,7 +257,7 @@ class GnmiSessionHandler: #if not exists: continue if isinstance(resource_value, str): resource_value = json.loads(resource_value) # pylint: disable=unused-variable - str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=True) + str_path, str_data = compose(resource_key, resource_value, self._yang_handler, delete=True, device_type=self.device_type) if str_path is None: continue # nothing to do with this resource_key #self._logger.info('---3') #self._logger.info(str(str_path)) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py index c3c52fa857aa569361083439546b5118b8457c3f..33c93ed79d8f90cc9a28d1c25d858415d0db1470 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/Acl.py @@ -18,6 +18,7 @@ from typing import Any, Dict, List, Tuple import libyang +from inter_device_translation import get_dict_helper from ._Handler import _Handler from .YangHandler import YangHandler @@ -43,11 +44,14 @@ _OC_TFS_FWD_ACTION = {v: k for k, v in _TFS_OC_FWD_ACTION.items()} class AclHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/device/endpoint/acl_ruleset' def get_path(self) -> str: - return '/openconfig-acl:acl' + return self._dict_helper.get_path('acl') def compose( # pylint: disable=too-many-locals self, @@ -66,7 +70,7 @@ class AclHandler(_Handler): path = f'/acl/acl-sets/acl-set[name={rs_name}][type={oc_type}]' return path, '' - yang_acl: libyang.DContainer = yang.get_data_path('/openconfig-acl:acl') + yang_acl: libyang.DContainer = yang.get_data_path(self._dict_helper.get_path('acl')) y_sets = yang_acl.create_path('acl-sets') y_set = y_sets.create_path(f'acl-set[name="{rs_name}"][type="{oc_type}"]') diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Component.py b/src/device/service/drivers/gnmi_openconfig/handlers/Component.py index fab4722330a398330d1025bcf85fe0d975812960..581ea0adfae6b77d31a95c8c8441fee57099fcc8 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/Component.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/Component.py @@ -17,15 +17,19 @@ from typing import Any, Dict, List, Tuple from common.proto.kpi_sample_types_pb2 import KpiSampleType from ._Handler import _Handler from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) -PATH_IF_CTR = '/openconfig-interfaces:interfaces/interface[name={:s}]/state/counters/{:s}' +# Path will be constructed dynamically using device translation #pylint: disable=abstract-method class ComponentHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/endpoints/endpoint' - def get_path(self) -> str: return '/openconfig-platform:components' + def get_path(self) -> str: return self._dict_helper.get_path('components') def parse( self, json_data : Dict, yang_handler : YangHandler @@ -36,7 +40,8 @@ class ComponentHandler(_Handler): json_data_valid = yang_handler.parse_to_dict(yang_components_path, json_data, fmt='json') entries = [] - for component in json_data_valid['components']['component']: + + for component in json_data_valid[self._dict_helper.get_object('components', plural=True)][self._dict_helper.get_object('components')]: LOGGER.debug('component={:s}'.format(str(component))) component_name = component['name'] @@ -59,12 +64,13 @@ class ComponentHandler(_Handler): endpoint = {'uuid': interface_name, 'type': '-'} endpoint['sample_types'] = { - KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED : PATH_IF_CTR.format(interface_name, 'in-octets' ), - KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED : PATH_IF_CTR.format(interface_name, 'out-octets'), - KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED : PATH_IF_CTR.format(interface_name, 'in-pkts' ), - KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: PATH_IF_CTR.format(interface_name, 'out-pkts' ), + KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED : self._dict_helper.get_path('interface_counters', name=interface_name, counter='in-octets'), + KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED : self._dict_helper.get_path('interface_counters', name=interface_name, counter='out-octets'), + KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED : self._dict_helper.get_path('interface_counters', name=interface_name, counter='in-pkts'), + KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: self._dict_helper.get_path('interface_counters', name=interface_name, counter='out-pkts'), } - entries.append(('/endpoints/endpoint[{:s}]'.format(endpoint['uuid']), endpoint)) + resource_key = self._dict_helper.get_resource_key('endpoints_endpoint', uuid=endpoint['uuid']) + entries.append((resource_key, endpoint)) return entries diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py b/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py index d59bff7a61cd1ef468f8220456bf7434b16bb0b6..4619c5a6d41b719d9e613359a86e440d1cec789a 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/Interface.py @@ -17,12 +17,17 @@ from typing import Any, Dict, List, Tuple from ._Handler import _Handler from .Tools import get_bool, get_int, get_str from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) class InterfaceHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/interface/subinterface' - def get_path(self) -> str: return '/openconfig-interfaces:interfaces' + def get_path(self) -> str: + return self._dict_helper.get_path('interfaces') def compose( self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False @@ -31,8 +36,7 @@ class InterfaceHandler(_Handler): sif_index = get_int(resource_value, 'index', 0) # 0 if delete: - PATH_TMPL = '/interfaces/interface[name={:s}]/subinterfaces/subinterface[index={:d}]' - str_path = PATH_TMPL.format(if_name, sif_index) + str_path = self._dict_helper.get_path('interface_subinterface', name=if_name, index=sif_index) str_data = json.dumps({}) root_node : libyang.DContainer = yang_handler.get_data_path( @@ -58,7 +62,7 @@ class InterfaceHandler(_Handler): address_prefix = get_int (resource_value, 'address_prefix') # 24 mtu = get_int (resource_value, 'mtu' ) # 1500 - yang_ifs : libyang.DContainer = yang_handler.get_data_path('/openconfig-interfaces:interfaces') + yang_ifs : libyang.DContainer = yang_handler.get_data_path(self._dict_helper.get_path('interfaces')) yang_if_path = 'interface[name="{:s}"]'.format(if_name) yang_if : libyang.DContainer = yang_ifs.create_path(yang_if_path) yang_if.create_path('config/name', if_name ) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py b/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py index f9aa55f4855274f4676c7238daa1c64394b238f8..19f79c26e867351ae5ce4e269013b1b469dfce35 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/InterfaceCounter.py @@ -16,13 +16,18 @@ import json, libyang, logging from typing import Any, Dict, List, Tuple from ._Handler import _Handler from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) #pylint: disable=abstract-method class InterfaceCounterHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/interface/counters' - def get_path(self) -> str: return '/openconfig-interfaces:interfaces/interface/state/counters' + def get_path(self) -> str: + return self._dict_helper.get_path('interface_counters_path') def parse( self, json_data : Dict, yang_handler : YangHandler @@ -58,7 +63,7 @@ class InterfaceCounterHandler(_Handler): } LOGGER.debug('interface = {:s}'.format(str(interface))) - entry_interface_key = '/interface[{:s}]'.format(interface_name) + entry_interface_key = self._dict_helper.get_resource_key('interface', name=interface_name) entries.append((entry_interface_key, _interface)) return entries diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py index 2c4be4e8a8efe5052bb64aac264bc5716a3aeae8..811a52e0bcaae171f21f0b2b4804c171c6bf4cbb 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstance.py @@ -17,6 +17,7 @@ from typing import Any, Dict, List, Tuple from ._Handler import _Handler from .Tools import get_str from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) @@ -38,8 +39,12 @@ MAP_NETWORK_INSTANCE_TYPE = { } class NetworkInstanceHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type) + def get_resource_key(self) -> str: return '/network_instance' - def get_path(self) -> str: return '/openconfig-network-instance:network-instances' + def get_path(self) -> str: + return self._dict_helper.get_path('network_instances') def compose( self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False @@ -47,21 +52,20 @@ class NetworkInstanceHandler(_Handler): ni_name = get_str(resource_value, 'name') # test-svc if delete: - PATH_TMPL = '/network-instances/network-instance[name={:s}]' - str_path = PATH_TMPL.format(ni_name) + str_path = self._dict_helper.get_path('network_instance', name=ni_name) str_data = json.dumps({}) return str_path, str_data ni_type = get_str(resource_value, 'type') # L3VRF / L2VSI / ... ni_type = MAP_NETWORK_INSTANCE_TYPE.get(ni_type, ni_type) - str_path = '/network-instances/network-instance[name={:s}]'.format(ni_name) + str_path = self._dict_helper.get_path('network_instance', name=ni_name) #str_data = json.dumps({ # 'name': ni_name, # 'config': {'name': ni_name, 'type': ni_type}, #}) - yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances') + yang_nis : libyang.DContainer = yang_handler.get_data_path(self._dict_helper.get_path('network_instances')) yang_ni_path = 'network-instance[name="{:s}"]'.format(ni_name) yang_ni : libyang.DContainer = yang_nis.create_path(yang_ni_path) yang_ni.create_path('config/name', ni_name) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py index f24cb8662789067c236a86f6159b042b8d67443e..443068551c81f1adba88e3fb723622d98ccdbf78 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceInterface.py @@ -17,14 +17,19 @@ from typing import Any, Dict, List, Tuple from ._Handler import _Handler from .Tools import get_int, get_str from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) IS_CEOS = True class NetworkInstanceInterfaceHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/network_instance/interface' - def get_path(self) -> str: return '/openconfig-network-instance:network-instances/network-instance/interfaces' + def get_path(self) -> str: + return self._dict_helper.get_path('network_instance_interfaces') def compose( self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False @@ -36,8 +41,7 @@ class NetworkInstanceInterfaceHandler(_Handler): if IS_CEOS: ni_if_id = if_name - PATH_TMPL = '/network-instances/network-instance[name={:s}]/interfaces/interface[id={:s}]' - str_path = PATH_TMPL.format(ni_name, ni_if_id) + str_path = self._dict_helper.get_path('network_instance_interface', name=ni_name, interface_id=ni_if_id) if delete: str_data = json.dumps({}) @@ -48,7 +52,7 @@ class NetworkInstanceInterfaceHandler(_Handler): # 'config': {'id': if_id, 'interface': if_name, 'subinterface': sif_index}, #}) - yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances') + yang_nis : libyang.DContainer = yang_handler.get_data_path(self._dict_helper.get_path('network_instances')) yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name)) yang_ni_ifs : libyang.DContainer = yang_ni.create_path('interfaces') yang_ni_if_path = 'interface[id="{:s}"]'.format(ni_if_id) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py index f83597056f4ea3eee11a0a6c59adbb100ba697cd..f027a8b47cbe733f54cd2f7500c9f40aea4f7bff 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceProtocol.py @@ -17,13 +17,17 @@ from typing import Any, Dict, List, Tuple from ._Handler import _Handler from .Tools import get_str from .YangHandler import YangHandler +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) class NetworkInstanceProtocolHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/network_instance/protocols' def get_path(self) -> str: - return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol' + return self._dict_helper.get_path('network_instance_protocols') def compose( self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False @@ -34,8 +38,7 @@ class NetworkInstanceProtocolHandler(_Handler): if ':' not in identifier: identifier = 'openconfig-policy-types:{:s}'.format(identifier) - PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]' - str_path = PATH_TMPL.format(ni_name, identifier, proto_name) + str_path = self._dict_helper.get_path('network_instance_protocol', name=ni_name, identifier=identifier, protocol_name=proto_name) if delete: str_data = json.dumps({}) @@ -56,7 +59,7 @@ class NetworkInstanceProtocolHandler(_Handler): # }]} #}) - yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances') + yang_nis : libyang.DContainer = yang_handler.get_data_path(self._dict_helper.get_path('network_instances')) yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name)) yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols') yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py index 78d77c8cdeb9b47107941e55e013da6d99bdd769..93295cc46b8c3c3b88b8b91961e25b38ad5a8dd0 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/NetworkInstanceStaticRoute.py @@ -21,9 +21,12 @@ from .YangHandler import YangHandler LOGGER = logging.getLogger(__name__) class NetworkInstanceStaticRouteHandler(_Handler): + def __init__(self, device_type=None): + self._dict_helper = get_dict_helper(device_type or 'oc') + def get_resource_key(self) -> str: return '/network_instance/protocols/static_route' def get_path(self) -> str: - return '/openconfig-network-instance:network-instances/network-instance/protocols/protocol/static-routes' + return self._dict_helper.get_path('network_instance_static_routes') def compose( self, resource_key : str, resource_value : Dict, yang_handler : YangHandler, delete : bool = False @@ -37,9 +40,7 @@ class NetworkInstanceStaticRouteHandler(_Handler): identifier = 'openconfig-policy-types:{:s}'.format(identifier) if delete: - PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols' - PATH_TMPL += '/protocol[identifier={:s}][name={:s}]/static-routes/static[prefix={:s}]' - str_path = PATH_TMPL.format(ni_name, identifier, proto_name, prefix) + str_path = self._dict_helper.get_path('network_instance_static_route', name=ni_name, identifier=identifier, protocol_name=proto_name, prefix=prefix) str_data = json.dumps({}) return str_path, str_data @@ -49,8 +50,7 @@ class NetworkInstanceStaticRouteHandler(_Handler): if index is None: index = 'AUTO_{:d}_{:s}'.format(metric, next_hop) - PATH_TMPL = '/network-instances/network-instance[name={:s}]/protocols/protocol[identifier={:s}][name={:s}]' - str_path = PATH_TMPL.format(ni_name, identifier, proto_name) + str_path = self._dict_helper.get_path('network_instance_protocol', name=ni_name, identifier=identifier, protocol_name=proto_name) #str_data = json.dumps({ # 'identifier': identifier, 'name': name, # 'config': {'identifier': identifier, 'name': name, 'enabled': True}, @@ -66,7 +66,7 @@ class NetworkInstanceStaticRouteHandler(_Handler): # }]} #}) - yang_nis : libyang.DContainer = yang_handler.get_data_path('/openconfig-network-instance:network-instances') + yang_nis : libyang.DContainer = yang_handler.get_data_path(self._dict_helper.get_path('network_instances')) yang_ni : libyang.DContainer = yang_nis.create_path('network-instance[name="{:s}"]'.format(ni_name)) yang_ni_prs : libyang.DContainer = yang_ni.create_path('protocols') yang_ni_pr_path = 'protocol[identifier="{:s}"][name="{:s}"]'.format(identifier, proto_name) diff --git a/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py b/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py index 3ce655353ecf78360931a008f7c69bb732749ea0..23b7fe5ec5e89e05c9808b90cabaf01764fbb6f3 100644 --- a/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py +++ b/src/device/service/drivers/gnmi_openconfig/handlers/__init__.py @@ -29,15 +29,6 @@ from .YangHandler import YangHandler LOGGER = logging.getLogger(__name__) -comph = ComponentHandler() -ifaceh = InterfaceHandler() -ifctrh = InterfaceCounterHandler() -nih = NetworkInstanceHandler() -niifh = NetworkInstanceInterfaceHandler() -niph = NetworkInstanceProtocolHandler() -nisrh = NetworkInstanceStaticRouteHandler() -aclh = AclHandler() - ALL_RESOURCE_KEYS = [ RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, @@ -45,47 +36,65 @@ ALL_RESOURCE_KEYS = [ RESOURCE_ACL, ] -RESOURCE_KEY_MAPPER = { - RESOURCE_ENDPOINTS : comph.get_resource_key(), - RESOURCE_INTERFACES : ifaceh.get_resource_key(), - RESOURCE_NETWORK_INSTANCES : nih.get_resource_key(), - RESOURCE_ACL : aclh.get_resource_key(), -} +RESOURCE_KEY_MAPPER = {} +PATH_MAPPER = {} +RESOURCE_KEY_TO_HANDLER = {} +PATH_TO_HANDLER = {} + +def _load_device_specific_mappings(device_type): + global RESOURCE_KEY_MAPPER, PATH_MAPPER, RESOURCE_KEY_TO_HANDLER, PATH_TO_HANDLER + + comph = ComponentHandler(device_type) + ifaceh = InterfaceHandler(device_type) + ifctrh = InterfaceCounterHandler(device_type) + nih = NetworkInstanceHandler(device_type) + niifh = NetworkInstanceInterfaceHandler(device_type) + niph = NetworkInstanceProtocolHandler(device_type) + nisrh = NetworkInstanceStaticRouteHandler(device_type) + aclh = AclHandler(device_type) + + RESOURCE_KEY_MAPPER = { + RESOURCE_ENDPOINTS : comph.get_resource_key(), + RESOURCE_INTERFACES : ifaceh.get_resource_key(), + RESOURCE_NETWORK_INSTANCES : nih.get_resource_key(), + RESOURCE_ACL : aclh.get_resource_key(), + } -PATH_MAPPER = { - '/components' : comph.get_path(), - '/components/component' : comph.get_path(), - '/interfaces' : ifaceh.get_path(), - '/network-instances' : nih.get_path(), - '/acl' : aclh.get_path(), -} + PATH_MAPPER = { + '/components' : comph.get_path(), + '/components/component' : comph.get_path(), + '/interfaces' : ifaceh.get_path(), + '/network-instances' : nih.get_path(), + '/acl' : aclh.get_path(), + } -RESOURCE_KEY_TO_HANDLER = { - comph.get_resource_key() : comph, - ifaceh.get_resource_key() : ifaceh, - ifctrh.get_resource_key() : ifctrh, - nih.get_resource_key() : nih, - niifh.get_resource_key() : niifh, - niph.get_resource_key() : niph, - nisrh.get_resource_key() : nisrh, - aclh.get_resource_key() : aclh, -} + RESOURCE_KEY_TO_HANDLER = { + comph.get_resource_key() : comph, + ifaceh.get_resource_key() : ifaceh, + ifctrh.get_resource_key() : ifctrh, + nih.get_resource_key() : nih, + niifh.get_resource_key() : niifh, + niph.get_resource_key() : niph, + nisrh.get_resource_key() : nisrh, + aclh.get_resource_key() : aclh, + } -PATH_TO_HANDLER = { - comph.get_path() : comph, - ifaceh.get_path() : ifaceh, - ifctrh.get_path() : ifctrh, - nih.get_path() : nih, - niifh.get_path() : niifh, - niph.get_path() : niph, - nisrh.get_path() : nisrh, - aclh.get_path() : aclh, -} + PATH_TO_HANDLER = { + comph.get_path() : comph, + ifaceh.get_path() : ifaceh, + ifctrh.get_path() : ifctrh, + nih.get_path() : nih, + niifh.get_path() : niifh, + niph.get_path() : niph, + nisrh.get_path() : nisrh, + aclh.get_path() : aclh, + } def get_handler( resource_key : Optional[str] = None, path : Optional[str] = None, - raise_if_not_found=True + raise_if_not_found=True, device_type: str = None ) -> Optional[_Handler]: + _load_device_specific_mappings(device_type) if (resource_key is None) == (path is None): MSG = 'Exactly one of resource_key({:s}) or path({:s}) must be specified' raise Exception(MSG.format(str(resource_key), str(path))) # pylint: disable=broad-exception-raised @@ -107,19 +116,19 @@ def get_handler( raise Exception(MSG.format(str(path), str(path_schema))) return handler -def get_path(resource_key : str) -> str: - handler = get_handler(resource_key=resource_key) +def get_path(resource_key : str, device_type: str = None) -> str: + handler = get_handler(resource_key=resource_key, device_type=device_type) return handler.get_path() def parse( - str_path : str, value : Union[Dict, List], yang_handler : YangHandler + str_path : str, value : Union[Dict, List], yang_handler : YangHandler, device_type: str = None ) -> List[Tuple[str, Dict[str, Any]]]: - handler = get_handler(path=str_path) + handler = get_handler(path=str_path, device_type=device_type) return handler.parse(value, yang_handler) def compose( resource_key : str, resource_value : Union[Dict, List], - yang_handler : YangHandler, delete : bool = False + yang_handler : YangHandler, delete : bool = False, device_type: str = None ) -> Tuple[str, str]: - handler = get_handler(resource_key=resource_key) + handler = get_handler(resource_key=resource_key, device_type=device_type) return handler.compose(resource_key, resource_value, yang_handler, delete=delete) diff --git a/src/device/service/drivers/openconfig/OpenConfigDriver.py b/src/device/service/drivers/openconfig/OpenConfigDriver.py index 4bf7be22c1d474a4ddf91d23f96f412d631057b2..0d079302f823b8374facfb9f0ca943be0820ea95 100644 --- a/src/device/service/drivers/openconfig/OpenConfigDriver.py +++ b/src/device/service/drivers/openconfig/OpenConfigDriver.py @@ -110,7 +110,7 @@ class NetconfSessionHandler: @RETRY_DECORATOR def get(self, filter=None, with_defaults=None): # pylint: disable=redefined-builtin with self.__lock: - if self.__vendor == 'JUNIPER'and not 'component' in str(filter): + if self.__vendor == 'JUNIPER' and not 'component' in str(filter): return self.__manager.get_config(source="running", filter=filter, with_defaults=with_defaults) else: return self.__manager.get(filter=filter, with_defaults=with_defaults) @@ -167,9 +167,9 @@ class SamplesCache: try: now = datetime.timestamp(datetime.utcnow()) if self.__timestamp is not None and (now - self.__timestamp) < SAMPLE_EVICTION_SECONDS: return - str_filter = get_filter(SAMPLE_RESOURCE_KEY) + str_filter = get_filter(SAMPLE_RESOURCE_KEY, device_type=self.__netconf_handler.vendor) xml_data = self.__netconf_handler.get(filter=str_filter).data_ele - interface_samples = parse(SAMPLE_RESOURCE_KEY, xml_data) + interface_samples = parse(SAMPLE_RESOURCE_KEY, xml_data, device_type=self.__netconf_handler.vendor) for interface,samples in interface_samples: match = RE_GET_ENDPOINT_FROM_INTERFACE_KEY.match(interface) if match is None: continue @@ -228,7 +228,7 @@ def edit_config( 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, message_renderer=netconf_handler.message_renderer) + resource_key, resource_value, delete=delete, vendor=netconf_handler.vendor, message_renderer=netconf_handler.message_renderer, device_type=netconf_handler.vendor) 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( @@ -318,12 +318,12 @@ class OpenConfigDriver(_Driver): str_resource_name = 'resource_key[#{:d}]'.format(i) try: chk_string(str_resource_name, resource_key, allow_empty=False) - str_filter = get_filter(resource_key) + str_filter = get_filter(resource_key, device_type=self.__netconf_handler.vendor) #self.__logger.debug('[GetConfig] str_filter = {:s}'.format(str(str_filter))) if str_filter is None: str_filter = resource_key xml_data = self.__netconf_handler.get(filter=str_filter).data_ele if isinstance(xml_data, Exception): raise xml_data - results.extend(parse(resource_key, xml_data)) + results.extend(parse(resource_key, xml_data, device_type=self.__netconf_handler.vendor)) except Exception as e: # pylint: disable=broad-except MSG = 'Exception retrieving {:s}: {:s}' self.__logger.exception(MSG.format(str_resource_name, str(resource_key))) diff --git a/src/device/service/drivers/openconfig/templates/Acl.py b/src/device/service/drivers/openconfig/templates/Acl.py index 7845e8fcffcc7dd1a34369ea9675041295371a52..9ba37c1c6487c7af54074ce7421ae821ff528c97 100644 --- a/src/device/service/drivers/openconfig/templates/Acl.py +++ b/src/device/service/drivers/openconfig/templates/Acl.py @@ -16,110 +16,112 @@ import logging, lxml.etree as ET from typing import Any, Dict, List, Tuple from .Namespace import NAMESPACES from .Tools import add_value_from_tag +from inter_device_translation import get_dict_helper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_ACL_SET = "//ocacl:acl/ocacl:acl-sets/ocacl:acl-set" -XPATH_A_ACL_ENTRY = ".//ocacl:acl-entries/ocacl:acl-entry" -XPATH_A_IPv4 = ".//ocacl:ipv4/ocacl:config" -XPATH_A_TRANSPORT = ".//ocacl:transport/ocacl:config" -XPATH_A_ACTIONS = ".//ocacl:actions/ocacl:config" - -XPATH_INTERFACE = "//ocacl:acl/ocacl:interfaces/ocacl:interface" -XPATH_I_INGRESS = ".//ocacl:ingress-acl-sets/ocacl:ingress-acl-set" -XPATH_I_EGRESS = ".//ocacl:egress-acl-sets/ocacl:egress-acl-set" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_acl_set = "//" + dict_helper.get_path('acl_set') + xpath_acl_entry = ".//" + dict_helper.get_path('acl_entry') + xpath_acl_ipv4 = ".//" + dict_helper.get_path('acl_ipv4') + xpath_acl_transport = ".//" + dict_helper.get_path('acl_transport') + xpath_acl_actions = ".//" + dict_helper.get_path('acl_actions') + xpath_acl_interface = "//" + dict_helper.get_path('acl_interface') + xpath_acl_ingress = ".//" + dict_helper.get_path('acl_ingress') + xpath_acl_egress = ".//" + dict_helper.get_path('acl_egress') #LOGGER.info('[ACL] xml_data = {:s}'.format(str(ET.tostring(xml_data)))) response = [] acl = {} name = {} - for xml_acl in xml_data.xpath(XPATH_ACL_SET, namespaces=NAMESPACES): + for xml_acl in xml_data.xpath(xpath_acl_set, namespaces=NAMESPACES): #LOGGER.info('xml_acl = {:s}'.format(str(ET.tostring(xml_acl)))) - acl_name = xml_acl.find('ocacl:name', namespaces=NAMESPACES) + acl_name = find_element(xml_acl, 'acl_name', device_type, NAMESPACES) if acl_name is None or acl_name.text is None: continue add_value_from_tag(name, 'name', acl_name) - acl_type = xml_acl.find('ocacl:type', namespaces=NAMESPACES) + acl_type = find_element(xml_acl, 'acl_type', device_type, NAMESPACES) add_value_from_tag(acl, 'type', acl_type) - for xml_acl_entries in xml_acl.xpath(XPATH_A_ACL_ENTRY, namespaces=NAMESPACES): + for xml_acl_entries in xml_acl.xpath(xpath_acl_entry, namespaces=NAMESPACES): - acl_id = xml_acl_entries.find('ocacl:sequence-id', namespaces=NAMESPACES) + acl_id = find_element(xml_acl_entries, 'acl_sequence_id', device_type, NAMESPACES) add_value_from_tag(acl, 'sequence-id', acl_id) LOGGER.info('xml_acl_id = {:s}'.format(str(ET.tostring(acl_id)))) - for xml_ipv4 in xml_acl_entries.xpath(XPATH_A_IPv4, namespaces=NAMESPACES): + for xml_ipv4 in xml_acl_entries.xpath(xpath_acl_ipv4, namespaces=NAMESPACES): - ipv4_source = xml_ipv4.find('ocacl:source-address', namespaces=NAMESPACES) + ipv4_source = find_element(xml_ipv4, 'acl_source_address', device_type, NAMESPACES) add_value_from_tag(acl, 'source-address' , ipv4_source) - ipv4_destination = xml_ipv4.find('ocacl:destination-address', namespaces=NAMESPACES) + ipv4_destination = find_element(xml_ipv4, 'acl_destination_address', device_type, NAMESPACES) add_value_from_tag(acl, 'destination-address' , ipv4_destination) - ipv4_protocol = xml_ipv4.find('ocacl:protocol', namespaces=NAMESPACES) + ipv4_protocol = find_element(xml_ipv4, 'acl_protocol', device_type, NAMESPACES) add_value_from_tag(acl, 'protocol' , ipv4_protocol) - ipv4_dscp = xml_ipv4.find('ocacl:dscp', namespaces=NAMESPACES) + ipv4_dscp = find_element(xml_ipv4, 'acl_dscp', device_type, NAMESPACES) add_value_from_tag(acl, 'dscp' , ipv4_dscp) - ipv4_hop_limit = xml_ipv4.find('ocacl:hop-limit', namespaces=NAMESPACES) + ipv4_hop_limit = find_element(xml_ipv4, 'acl_hop_limit', device_type, NAMESPACES) add_value_from_tag(acl, 'hop-limit' , ipv4_hop_limit) - for xml_transport in xml_acl_entries.xpath(XPATH_A_TRANSPORT, namespaces=NAMESPACES): + for xml_transport in xml_acl_entries.xpath(xpath_acl_transport, namespaces=NAMESPACES): - transport_source = xml_transport.find('ocacl:source-port', namespaces=NAMESPACES) + transport_source = find_element(xml_transport, 'acl_source_port', device_type, NAMESPACES) add_value_from_tag(acl, 'source-port' ,transport_source) - transport_destination = xml_transport.find('ocacl:destination-port', namespaces=NAMESPACES) + transport_destination = find_element(xml_transport, 'acl_destination_port', device_type, NAMESPACES) add_value_from_tag(acl, 'destination-port' ,transport_destination) - transport_tcp_flags = xml_transport.find('ocacl:tcp-flags', namespaces=NAMESPACES) + transport_tcp_flags = find_element(xml_transport, 'acl_tcp_flags', device_type, NAMESPACES) add_value_from_tag(acl, 'tcp-flags' ,transport_tcp_flags) - for xml_action in xml_acl_entries.xpath(XPATH_A_ACTIONS, namespaces=NAMESPACES): + for xml_action in xml_acl_entries.xpath(xpath_acl_actions, namespaces=NAMESPACES): - action = xml_action.find('ocacl:forwarding-action', namespaces=NAMESPACES) + action = find_element(xml_action, 'acl_forwarding_action', device_type, NAMESPACES) add_value_from_tag(acl, 'forwarding-action' ,action) - log_action = xml_action.find('ocacl:log-action', namespaces=NAMESPACES) + log_action = find_element(xml_action, 'acl_log_action', device_type, NAMESPACES) add_value_from_tag(acl, 'log-action' ,log_action) - resource_key = '/acl/acl-set[{:s}][{:s}]/acl-entry[{:s}]'.format( - name['name'], acl['type'], acl['sequence-id']) + resource_key = get_resource_key('acl_set_entry', device_type, + name=name['name'], type=acl['type'], sequence_id=acl['sequence-id']) response.append((resource_key,acl)) - for xml_interface in xml_data.xpath(XPATH_INTERFACE, namespaces=NAMESPACES): + for xml_interface in xml_data.xpath(xpath_acl_interface, namespaces=NAMESPACES): interface = {} - interface_id = xml_interface.find('ocacl:id', namespaces=NAMESPACES) + interface_id = find_element(xml_interface, 'acl_interface_id', device_type, NAMESPACES) add_value_from_tag(interface, 'id' , interface_id) - for xml_ingress in xml_interface.xpath(XPATH_I_INGRESS, namespaces=NAMESPACES): + for xml_ingress in xml_interface.xpath(xpath_acl_ingress, namespaces=NAMESPACES): - i_name = xml_ingress.find('ocacl:set-name-ingress', namespaces=NAMESPACES) + i_name = find_element(xml_ingress, 'acl_set_name_ingress', device_type, NAMESPACES) add_value_from_tag(interface, 'ingress-set-name' , i_name) - i_type = xml_ingress.find('ocacl:type-ingress', namespaces=NAMESPACES) + i_type = find_element(xml_ingress, 'acl_type_ingress', device_type, NAMESPACES) add_value_from_tag(interface, 'ingress-type' , i_type) - resource_key = '/acl/interfaces/ingress[{:s}][{:s}]'.format( - name['name'], acl['type']) + resource_key = get_resource_key('acl_interfaces_ingress', device_type, + name=name['name'], type=acl['type']) response.append((resource_key,interface)) - for xml_egress in xml_interface.xpath(XPATH_I_EGRESS, namespaces=NAMESPACES): + for xml_egress in xml_interface.xpath(xpath_acl_egress, namespaces=NAMESPACES): - e_name = xml_egress.find('ocacl:set-name-egress', namespaces=NAMESPACES) + e_name = find_element(xml_egress, 'acl_set_name_egress', device_type, NAMESPACES) add_value_from_tag(interface, 'egress-set-name' , e_name) - e_type = xml_egress.find('ocacl:type-egress', namespaces=NAMESPACES) + e_type = find_element(xml_egress, 'acl_type_egress', device_type, NAMESPACES) add_value_from_tag(interface, 'egress-type' , e_type) - resource_key = '/acl/interfaces/egress[{:s}][{:s}]'.format( - name['name'], acl['type']) + resource_key = get_resource_key('acl_interfaces_egress', device_type, + name=name['name'], type=acl['type']) response.append((resource_key,interface)) return response diff --git a/src/device/service/drivers/openconfig/templates/EndPoints.py b/src/device/service/drivers/openconfig/templates/EndPoints.py index dc607cb6763d38153cada21d9e2794d4ea128f07..c628b37884afacd17d60b72ec3e48a5c4d7f65ce 100644 --- a/src/device/service/drivers/openconfig/templates/EndPoints.py +++ b/src/device/service/drivers/openconfig/templates/EndPoints.py @@ -17,18 +17,22 @@ from typing import Any, Dict, List, Tuple from common.proto.kpi_sample_types_pb2 import KpiSampleType from .Namespace import NAMESPACES from .Tools import add_value_from_collection, add_value_from_tag +from inter_device_translation import get_dict_helper, DictHelper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_PORTS = "//ocp:components/ocp:component" -XPATH_IFACE_COUNTER = "//oci:interfaces/oci:interface[oci:name='{:s}']/state/counters/{:s}" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_ports = "//" + dict_helper.get_path('ports') + xpath_iface_counter = "//" + dict_helper.get_path('interface_counters') + response = [] - for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES): + for xml_component in xml_data.xpath(xpath_ports, namespaces=NAMESPACES): #LOGGER.info('xml_component = {:s}'.format(str(ET.tostring(xml_component)))) - component_type = xml_component.find('ocp:state/ocp:type', namespaces=NAMESPACES) + component_type = find_element(xml_component, 'ep_component_type', device_type, NAMESPACES) if component_type is None or component_type.text is None: continue component_type = component_type.text if component_type not in {'PORT', 'oc-platform-types:PORT', 'idx:PORT'}: continue @@ -37,23 +41,22 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: endpoint = {} - component_name = xml_component.find('ocp:name', namespaces=NAMESPACES) + component_name = find_element(xml_component, 'ep_component_name', device_type, NAMESPACES) if component_name is None or component_name.text is None: continue add_value_from_tag(endpoint, 'uuid', component_name) - component_type = xml_component.find( - 'ocpp:port/ocpp:breakout-mode/ocpp:state/ocpp:channel-speed', namespaces=NAMESPACES) + component_type = find_element(xml_component, 'ep_port_channel_speed', device_type, NAMESPACES) add_value_from_tag(endpoint, 'type', component_type) if 'type' not in endpoint: endpoint['type'] = '-' sample_types = { - KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED : XPATH_IFACE_COUNTER.format(endpoint['uuid'], 'in-octets' ), - KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED : XPATH_IFACE_COUNTER.format(endpoint['uuid'], 'out-octets'), - KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED : XPATH_IFACE_COUNTER.format(endpoint['uuid'], 'in-pkts' ), - KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: XPATH_IFACE_COUNTER.format(endpoint['uuid'], 'out-pkts' ), + KpiSampleType.KPISAMPLETYPE_BYTES_RECEIVED : "//" + dict_helper.get_path('interface_counters', interface_name=endpoint['uuid'], counter_name='in-octets'), + KpiSampleType.KPISAMPLETYPE_BYTES_TRANSMITTED : "//" + dict_helper.get_path('interface_counters', interface_name=endpoint['uuid'], counter_name='out-octets'), + KpiSampleType.KPISAMPLETYPE_PACKETS_RECEIVED : "//" + dict_helper.get_path('interface_counters', interface_name=endpoint['uuid'], counter_name='in-pkts'), + KpiSampleType.KPISAMPLETYPE_PACKETS_TRANSMITTED: "//" + dict_helper.get_path('interface_counters', interface_name=endpoint['uuid'], counter_name='out-pkts'), } add_value_from_collection(endpoint, 'sample_types', sample_types) if len(endpoint) == 0: continue - response.append(('/endpoints/endpoint[{:s}]'.format(endpoint['uuid']), endpoint)) + response.append((get_resource_key('endpoints_endpoint', device_type, uuid=endpoint['uuid']), endpoint)) return response diff --git a/src/device/service/drivers/openconfig/templates/Interfaces.py b/src/device/service/drivers/openconfig/templates/Interfaces.py index aea737100bcd980a097d2d2254750e44d59809a0..6f0b0474e83987e0dac9627b557b884408980c27 100644 --- a/src/device/service/drivers/openconfig/templates/Interfaces.py +++ b/src/device/service/drivers/openconfig/templates/Interfaces.py @@ -16,31 +16,31 @@ import logging, lxml.etree as ET from typing import Any, Dict, List, Tuple from .Namespace import NAMESPACES from .Tools import add_value_from_tag +from inter_device_translation import get_dict_helper, DictHelper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_INTERFACES = "//oci:interfaces/oci:interface" -XPATH_SUBINTERFACES = ".//oci:subinterfaces/oci:subinterface" -XPATH_IPV4ADDRESSES = ".//ociip:ipv4/ociip:addresses/ociip:address" -XPATH_IPV6ADDRESSES = ".//ociip:ipv6/ociip:addresses/ociip:address" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_interfaces = "//" + dict_helper.get_path('interfaces') + xpath_subinterfaces = ".//" + dict_helper.get_path('subinterfaces') + xpath_ipv4_addresses = ".//" + dict_helper.get_path('ipv4_addresses') + xpath_ipv6_addresses = ".//" + dict_helper.get_path('ipv6_addresses') response = [] - for xml_interface in xml_data.xpath(XPATH_INTERFACES, namespaces=NAMESPACES): + for xml_interface in xml_data.xpath(xpath_interfaces, namespaces=NAMESPACES): #LOGGER.info('xml_interface = {:s}'.format(str(ET.tostring(xml_interface)))) interface = {} - #interface_type = xml_interface.find('oci:config/oci:type', namespaces=NAMESPACES) - #add_value_from_tag(interface, 'type', interface_type) - - if xml_interface.find('oci:config/oci:type', namespaces=NAMESPACES) is not None: - interface_type = xml_interface.find('oci:config/oci:type', namespaces=NAMESPACES) - elif xml_interface.find('oci:state/oci:type', namespaces=NAMESPACES) is not None: - interface_type = xml_interface.find('oci:state/oci:type', namespaces=NAMESPACES) - else: continue + # Try to find interface type in config first, then state + interface_type = find_element(xml_interface, 'interface_type', device_type, NAMESPACES) + if interface_type is None: + interface_type = find_element(xml_interface, 'interface_state_type', device_type, NAMESPACES) + if interface_type is None: continue - interface_name = xml_interface.find('oci:name', namespaces=NAMESPACES) + interface_name = find_element(xml_interface, 'interface_name', device_type, NAMESPACES) if interface_name is None or interface_name.text is None: continue add_value_from_tag(interface, 'name', interface_name) @@ -51,13 +51,13 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: interface_type.text = interface_type.text.replace('idx:', '') #CISCO add_value_from_tag(interface, 'type', interface_type) - interface_mtu = xml_interface.find('oci:config/oci:mtu', namespaces=NAMESPACES) + interface_mtu = find_element(xml_interface, 'interface_mtu', device_type, NAMESPACES) add_value_from_tag(interface, 'mtu', interface_mtu, cast=int) - interface_description = xml_interface.find('oci:config/oci:description', namespaces=NAMESPACES) + interface_description = find_element(xml_interface, 'interface_description', device_type, NAMESPACES) add_value_from_tag(interface, 'description', interface_description) - for xml_subinterface in xml_interface.xpath(XPATH_SUBINTERFACES, namespaces=NAMESPACES): + for xml_subinterface in xml_interface.xpath(xpath_subinterfaces, namespaces=NAMESPACES): #LOGGER.info('xml_subinterface = {:s}'.format(str(ET.tostring(xml_subinterface)))) subinterface = {} @@ -67,16 +67,16 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: add_value_from_tag(subinterface, 'type', interface_type) - subinterface_index = xml_subinterface.find('oci:index', namespaces=NAMESPACES) + subinterface_index = find_element(xml_subinterface, 'subinterface_index', device_type, NAMESPACES) if subinterface_index is None or subinterface_index.text is None: continue add_value_from_tag(subinterface, 'index', subinterface_index, cast=int) - vlan_id = xml_subinterface.find('ocv:vlan/ocv:match/ocv:single-tagged/ocv:config/ocv:vlan-id', namespaces=NAMESPACES) + vlan_id = find_element(xml_subinterface, 'subinterface_vlan', device_type, NAMESPACES) add_value_from_tag(subinterface, 'vlan_id', vlan_id, cast=int) # TODO: implement support for multiple IP addresses per subinterface #ipv4_addresses = [] - for xml_ipv4_address in xml_subinterface.xpath(XPATH_IPV4ADDRESSES, namespaces=NAMESPACES): + for xml_ipv4_address in xml_subinterface.xpath(xpath_ipv4_addresses, namespaces=NAMESPACES): #LOGGER.info('xml_ipv4_address = {:s}'.format(str(ET.tostring(xml_ipv4_address)))) #ipv4_address = {} @@ -84,11 +84,11 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: #origin = xml_ipv4_address.find('ociip:state/ociip:origin', namespaces=NAMESPACES) #add_value_from_tag(ipv4_address, 'origin', origin) - address = xml_ipv4_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES) + address = find_element(xml_ipv4_address, 'ipv4_address', device_type, NAMESPACES) #add_value_from_tag(ipv4_address, 'ip', address) add_value_from_tag(subinterface, 'address_ip', address) - prefix = xml_ipv4_address.find('ociip:state/ociip:prefix-length', namespaces=NAMESPACES) + prefix = find_element(xml_ipv4_address, 'ipv4_prefix', device_type, NAMESPACES) #add_value_from_tag(ipv4_address, 'prefix_length', prefix) add_value_from_tag(subinterface, 'address_prefix', prefix, cast=int) @@ -97,17 +97,18 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: #add_value_from_collection(subinterface, 'ipv4_addresses', ipv4_addresses) - for xml_ipv6_address in xml_subinterface.xpath(XPATH_IPV6ADDRESSES, namespaces=NAMESPACES): + for xml_ipv6_address in xml_subinterface.xpath(xpath_ipv6_addresses, namespaces=NAMESPACES): #LOGGER.info('xml_ipv6_address = {:s}'.format(str(ET.tostring(xml_ipv6_address)))) - address = xml_ipv6_address.find('ociip:state/ociip:ip', namespaces=NAMESPACES) + address = find_element(xml_ipv6_address, 'ipv6_address', device_type, NAMESPACES) add_value_from_tag(subinterface, 'address_ipv6', address) - prefix = xml_ipv6_address.find('ociip:state/ociip:prefix-length', namespaces=NAMESPACES) + prefix = find_element(xml_ipv6_address, 'ipv6_prefix', device_type, NAMESPACES) add_value_from_tag(subinterface, 'address_prefix_v6', prefix, cast=int) if len(subinterface) == 0: continue - resource_key = '/interface[{:s}]/subinterface[{:s}]'.format(interface['name'], str(subinterface['index'])) + resource_key = get_resource_key('interface_subinterface', device_type, + name=interface['name'], index=str(subinterface['index'])) response.append((resource_key, subinterface)) if len(interface) == 0: continue @@ -115,36 +116,40 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: return response -def parse_counters(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse_counters(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_interfaces = "//" + dict_helper.get_path('interfaces') + response = [] - for xml_interface in xml_data.xpath(XPATH_INTERFACES, namespaces=NAMESPACES): + for xml_interface in xml_data.xpath(xpath_interfaces, namespaces=NAMESPACES): #LOGGER.info('[parse_counters] xml_interface = {:s}'.format(str(ET.tostring(xml_interface)))) interface = {} - interface_name = xml_interface.find('oci:name', namespaces=NAMESPACES) + interface_name = find_element(xml_interface, 'interface_name', device_type, NAMESPACES) if interface_name is None or interface_name.text is None: continue add_value_from_tag(interface, 'name', interface_name) - interface_in_pkts = xml_interface.find('oci:state/oci:counters/oci:in-pkts', namespaces=NAMESPACES) + interface_in_pkts = find_element(xml_interface, 'interface_counters_in_pkts', device_type, NAMESPACES) add_value_from_tag(interface, 'in-pkts', interface_in_pkts, cast=int) - interface_in_octets = xml_interface.find('oci:state/oci:counters/oci:in-octets', namespaces=NAMESPACES) + interface_in_octets = find_element(xml_interface, 'interface_counters_in_octets', device_type, NAMESPACES) add_value_from_tag(interface, 'in-octets', interface_in_octets, cast=int) - interface_in_errors = xml_interface.find('oci:state/oci:counters/oci:in-errors', namespaces=NAMESPACES) + interface_in_errors = find_element(xml_interface, 'interface_counters_in_errors', device_type, NAMESPACES) add_value_from_tag(interface, 'in-errors', interface_in_errors, cast=int) - interface_out_octets = xml_interface.find('oci:state/oci:counters/oci:out-octets', namespaces=NAMESPACES) + interface_out_octets = find_element(xml_interface, 'interface_counters_out_octets', device_type, NAMESPACES) add_value_from_tag(interface, 'out-octets', interface_out_octets, cast=int) - interface_out_pkts = xml_interface.find('oci:state/oci:counters/oci:out-pkts', namespaces=NAMESPACES) + interface_out_pkts = find_element(xml_interface, 'interface_counters_out_pkts', device_type, NAMESPACES) add_value_from_tag(interface, 'out-pkts', interface_out_pkts, cast=int) - interface_out_errors = xml_interface.find('oci:state/oci:counters/oci:out-errors', namespaces=NAMESPACES) + interface_out_errors = find_element(xml_interface, 'interface_counters_out_errors', device_type, NAMESPACES) add_value_from_tag(interface, 'out-errors', interface_out_errors, cast=int) - interface_out_discards = xml_interface.find('oci:state/oci:counters/oci:out-discards', namespaces=NAMESPACES) + interface_out_discards = find_element(xml_interface, 'interface_counters_out_discards', device_type, NAMESPACES) add_value_from_tag(interface, 'out-discards', interface_out_discards, cast=int) #LOGGER.info('[parse_counters] interface = {:s}'.format(str(interface))) diff --git a/src/device/service/drivers/openconfig/templates/Inventory.py b/src/device/service/drivers/openconfig/templates/Inventory.py index d54d21d47aa1ed7e821e2c8572cc19f481a406f7..751f4a428f13a4989e97910877a90a9e6dddb7e4 100644 --- a/src/device/service/drivers/openconfig/templates/Inventory.py +++ b/src/device/service/drivers/openconfig/templates/Inventory.py @@ -16,11 +16,11 @@ import logging, lxml.etree as ET from typing import Any, Dict, List, Tuple from .Namespace import NAMESPACES from .Tools import add_value_from_tag +from inter_device_translation import get_dict_helper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_PORTS = "//ocp:components/ocp:component" - """ #Method Name: parse @@ -52,10 +52,14 @@ XPATH_PORTS = "//ocp:components/ocp:component" with the information extracted from the XML document components is returned. """ -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_ports = "//" + dict_helper.get_path('ports') + response = [] parent_types = {} - for xml_component in xml_data.xpath(XPATH_PORTS, namespaces=NAMESPACES): + for xml_component in xml_data.xpath(xpath_ports, namespaces=NAMESPACES): LOGGER.info('xml_component inventario = {:s}'.format(str(ET.tostring(xml_component)))) inventory = {} inventory['parent-component-references'] = '' @@ -64,82 +68,82 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: inventory['attributes'] = {} component_reference = [] - component_name = xml_component.find('ocp:name', namespaces=NAMESPACES) + component_name = find_element(xml_component, 'inv_component_name', device_type, NAMESPACES) if component_name is None or component_name.text is None: continue add_value_from_tag(inventory, 'name', component_name) - component_description = xml_component.find('ocp:state/ocp:description', namespaces=NAMESPACES) + component_description = find_element(xml_component, 'inv_component_description', device_type, NAMESPACES) if not component_description is None: add_value_from_tag(inventory['attributes'], 'description', component_description) - component_location = xml_component.find('ocp:state/ocp:location', namespaces=NAMESPACES) + component_location = find_element(xml_component, 'inv_component_location', device_type, NAMESPACES) if not component_location is None: add_value_from_tag(inventory['attributes'], 'location', component_location) - component_id = xml_component.find('ocp:state/ocp:id', namespaces=NAMESPACES) + component_id = find_element(xml_component, 'inv_component_id', device_type, NAMESPACES) if not component_id is None: add_value_from_tag(inventory['attributes'], 'id', component_id) - component_type = xml_component.find('ocp:state/ocp:type', namespaces=NAMESPACES) + component_type = find_element(xml_component, 'inv_component_type', device_type, NAMESPACES) if component_type is not None: component_type.text = component_type.text.replace('oc-platform-types:','') add_value_from_tag(inventory, 'class', component_type) if inventory['class'] == 'CPU' or inventory['class'] == 'STORAGE': continue - component_empty = xml_component.find('ocp:state/ocp:empty', namespaces=NAMESPACES) + component_empty = find_element(xml_component, 'inv_component_empty', device_type, NAMESPACES) if not component_empty is None: add_value_from_tag(inventory['attributes'], 'empty', component_empty) - component_parent = xml_component.find('ocp:state/ocp:parent', namespaces=NAMESPACES) + component_parent = find_element(xml_component, 'inv_component_parent', device_type, NAMESPACES) if not component_parent is None: add_value_from_tag(inventory, 'parent-component-references', component_parent) - component_HW = xml_component.find('ocp:state/ocp:hardware-version', namespaces=NAMESPACES) + component_HW = find_element(xml_component, 'inv_component_hardware_version', device_type, NAMESPACES) if not component_HW is None: add_value_from_tag(inventory['attributes'], 'hardware-rev', component_HW) - component_firmware_version = xml_component.find('ocp:state/ocp:firmware-version', namespaces=NAMESPACES) + component_firmware_version = find_element(xml_component, 'inv_component_firmware_version', device_type, NAMESPACES) if not component_firmware_version is None: add_value_from_tag(inventory['attributes'], 'firmware-rev', component_firmware_version) - component_SW = xml_component.find('ocp:state/ocp:software-version', namespaces=NAMESPACES) + component_SW = find_element(xml_component, 'inv_component_software_version', device_type, NAMESPACES) if not component_SW is None: add_value_from_tag(inventory['attributes'], 'software-rev', component_SW) - component_serial = xml_component.find('ocp:state/ocp:serial-no', namespaces=NAMESPACES) + component_serial = find_element(xml_component, 'inv_component_serial', device_type, NAMESPACES) if not component_serial is None: add_value_from_tag(inventory['attributes'], 'serial-num', component_serial) - component_mfg_name = xml_component.find('ocp:state/ocp:mfg-name', namespaces=NAMESPACES) + component_mfg_name = find_element(xml_component, 'inv_component_mfg_name', device_type, NAMESPACES) if not component_mfg_name is None: add_value_from_tag(inventory['attributes'], 'mfg-name', component_mfg_name) - component_removable = xml_component.find('ocp:state/ocp:removable', namespaces=NAMESPACES) + component_removable = find_element(xml_component, 'inv_component_removable', device_type, NAMESPACES) if not component_removable is None: add_value_from_tag(inventory['attributes'], 'removable', component_removable) - component_mfg_date = xml_component.find('ocp:state/ocp:mfg-date', namespaces=NAMESPACES) + component_mfg_date = find_element(xml_component, 'inv_component_mfg_date', device_type, NAMESPACES) if not component_mfg_date is None: add_value_from_tag(inventory['attributes'], 'mfg-date', component_mfg_date) #Transceiver Information - component_serial_t = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:serial-no', namespaces=NAMESPACES) + component_serial_t = find_element(xml_component, 'inv_transceiver_serial', device_type, NAMESPACES) if not component_serial_t is None: add_value_from_tag(inventory['attributes'], 'serial-num', component_serial_t) - component_present = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:present', namespaces=NAMESPACES) + component_present = find_element(xml_component, 'inv_transceiver_present', device_type, NAMESPACES) if component_present is not None and 'NOT_PRESENT' in component_present.text: continue - component_vendor = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:vendor', namespaces=NAMESPACES) + component_vendor = find_element(xml_component, 'inv_transceiver_vendor', device_type, NAMESPACES) if not component_vendor is None: add_value_from_tag(inventory['attributes'], 'vendor', component_vendor) - component_connector = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:connector-type', namespaces=NAMESPACES) + component_connector = find_element(xml_component, 'inv_transceiver_connector', device_type, NAMESPACES) if not component_connector is None: component_connector.text = component_connector.text.replace('oc-opt-types:','') add_value_from_tag(inventory['attributes'], 'connector-type', component_connector) - component_form = xml_component.find('ocptr:transceiver/ocptr:state/ocptr:form-factor', namespaces=NAMESPACES) + component_form = find_element(xml_component, 'inv_transceiver_form', device_type, NAMESPACES) if not component_form is None: component_form.text = component_form.text.replace('oc-opt-types:','') add_value_from_tag(inventory['attributes'], 'form-factor', component_form) @@ -149,7 +153,7 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: component_reference.extend([parent_types[inventory['parent-component-references']]]) - response.append(('/inventory/{:s}'.format(inventory['name']), inventory)) + response.append((get_resource_key('inventory_component', device_type, name=inventory['name']), inventory)) for tupla in response: if inventory['parent-component-references'] in tupla[0]: diff --git a/src/device/service/drivers/openconfig/templates/Namespace.py b/src/device/service/drivers/openconfig/templates/Namespace.py index 4604481bb666365752e33e9a8ef3bcf8523e6d1c..fd9af8cbda5355e1a2bedd7f7fdfa21586b54343 100644 --- a/src/device/service/drivers/openconfig/templates/Namespace.py +++ b/src/device/service/drivers/openconfig/templates/Namespace.py @@ -30,6 +30,18 @@ NAMESPACE_ROUTING_POLICY = 'http://openconfig.net/yang/routing-policy' NAMESPACE_VLAN = 'http://openconfig.net/yang/vlan' NAMESPACE_PLATFORM_TRANSCEIVER = 'http://openconfig.net/yang/platform/transceiver' + +NAMESPACE_IPI_INTERFACE = 'http://www.ipinfusion.com/yang/ocnos/ipi-interface' +NAMESPACE_IPI_INTERFACE_EXTENDED = 'http://www.ipinfusion.com/yang/ocnos/ipi-if-extended' +NAMESPACE_IPI_INTERFACE_IP = 'http://www.ipinfusion.com/yang/ocnos/ipi-if-ip' +NAMESPACE_IPI_NETWORK_INSTANCE = 'http://www.ipinfusion.com/yang/ocnos/ipi-network-instance' +NAMESPACE_IPI_VLAN = 'http://www.ipinfusion.com/yang/ocnos/ipi-vlan' +NAMESPACE_IPI_ACL = 'http://www.ipinfusion.com/yang/ocnos/ipi-acl' +NAMESPACE_IPI_ROUTING_POLICY = 'http://www.ipinfusion.com/yang/ocnos/ipi-routing-policy' +NAMESPACE_IPI_BGP_POLICY = 'http://www.ipinfusion.com/yang/ocnos/ipi-bgp-policy' +NAMESPACE_IPI_PLATFORM_PORT = 'http://www.ipinfusion.com/yang/ocnos/ipi-platform/port' +NAMESPACE_IPI_PLATFORM_TRANSCEIVER = 'http://www.ipinfusion.com/yang/ocnos/ipi-platform/transceiver' + NAMESPACES = { 'nc' : NAMESPACE_NETCONF, 'ocacl': NAMESPACE_ACL, @@ -46,4 +58,19 @@ NAMESPACES = { 'ocrp' : NAMESPACE_ROUTING_POLICY, 'ocv' : NAMESPACE_VLAN, 'ocptr': NAMESPACE_PLATFORM_TRANSCEIVER, + + 'ipii': NAMESPACE_IPI_INTERFACE, + 'ipiie': NAMESPACE_IPI_INTERFACE_EXTENDED, + 'ipiiip': NAMESPACE_IPI_INTERFACE_IP, + 'ipini': NAMESPACE_IPI_NETWORK_INSTANCE, + 'ipiv' : NAMESPACE_IPI_VLAN, + 'ipiacl': NAMESPACE_IPI_ACL, + 'ipirp': NAMESPACE_IPI_ROUTING_POLICY, + 'ipibp': NAMESPACE_IPI_BGP_POLICY, + 'ipipp': NAMESPACE_IPI_PLATFORM_PORT, + 'ipitr': NAMESPACE_IPI_PLATFORM_TRANSCEIVER, + + 'ipinfusion-interfaces': NAMESPACE_IPI_INTERFACE, + 'ipinfusion-network-instance': NAMESPACE_IPI_NETWORK_INSTANCE, + 'ipinfusion-network-instances': NAMESPACE_IPI_NETWORK_INSTANCE, } diff --git a/src/device/service/drivers/openconfig/templates/NetworkInstances.py b/src/device/service/drivers/openconfig/templates/NetworkInstances.py index 7fee1b76137e9d0d55451d2326c2a38c2d51d79e..ba542aa804a5b4ae00e8493e795a95aafa3f3beb 100644 --- a/src/device/service/drivers/openconfig/templates/NetworkInstances.py +++ b/src/device/service/drivers/openconfig/templates/NetworkInstances.py @@ -16,44 +16,37 @@ import logging, lxml.etree as ET from typing import Any, Dict, List, Tuple from .Namespace import NAMESPACES from .Tools import add_value_from_collection, add_value_from_tag +from inter_device_translation import get_dict_helper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_NETWORK_INSTANCES = "//ocni:network-instances/ocni:network-instance" -XPATH_NI_PROTOCOLS = ".//ocni:protocols/ocni:protocol" -XPATH_NI_TABLE_CONNECTS = ".//ocni:table-connections/ocni:table-connection" - -XPATH_NI_INTERFACE = ".//ocni:interfaces/ocni:interface" - -XPATH_NI_IIP_AP = ".//ocni:inter-instance-policies/ocni:apply-policy" -XPATH_NI_IIP_AP_IMPORT = ".//ocni:config/ocni:import-policy" -XPATH_NI_IIP_AP_EXPORT = ".//ocni:config/ocni:export-policy" - -XPATH_NI_CPOINTS = ".//ocni:connection-points/ocni:connection-point" -XPATH_NI_CPOINTS_ENDPOINT = ".//ocni:endpoints/ocni:endpoint/ocni:remote/ocni:config" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_network_instances = "//" + dict_helper.get_path('network_instances') + xpath_ni_protocols = ".//" + dict_helper.get_path('ni_protocols') + xpath_ni_table_connections = ".//" + dict_helper.get_path('ni_table_connections') + xpath_ni_interface = ".//" + dict_helper.get_path('ni_interface') + xpath_ni_apply_policy = ".//" + dict_helper.get_path('ni_apply_policy') + xpath_ni_import_policy = ".//" + dict_helper.get_path('ni_import_policy') + xpath_ni_export_policy = ".//" + dict_helper.get_path('ni_export_policy') + xpath_ni_connection_points = ".//" + dict_helper.get_path('ni_connection_points') + xpath_ni_endpoints = ".//" + dict_helper.get_path('ni_endpoints') response = [] - for xml_network_instance in xml_data.xpath(XPATH_NETWORK_INSTANCES, namespaces=NAMESPACES): + for xml_network_instance in xml_data.xpath(xpath_network_instances, namespaces=NAMESPACES): #LOGGER.info('xml_network_instance = {:s}'.format(str(ET.tostring(xml_network_instance)))) network_instance = {} - ni_name = xml_network_instance.find('ocni:name', namespaces=NAMESPACES) + ni_name = find_element(xml_network_instance, 'ni_name', device_type, NAMESPACES) if ni_name is None or ni_name.text is None: continue add_value_from_tag(network_instance, 'name', ni_name) - ''' - ni_type = xml_network_instance.find('ocni:config/ocni:type', namespaces=NAMESPACES) - ni_type.text = ni_type.text.replace('oc-ni-types:','') - add_value_from_tag(network_instance, 'type', ni_type) - ''' + - if xml_network_instance.find('ocni:config/ocni:type', namespaces=NAMESPACES) is not None: - ni_type = xml_network_instance.find('ocni:config/ocni:type', namespaces=NAMESPACES) - elif xml_network_instance.find('oci:state/oci:type', namespaces=NAMESPACES) is not None: - ni_type = xml_network_instance.find('oci:state/oci:type', namespaces=NAMESPACES) - else: + ni_type = find_element(xml_network_instance, 'ni_type', device_type, NAMESPACES) + if ni_type is None: continue if 'oc-ni-types:' in ni_type.text: ni_type.text = ni_type.text.replace('oc-ni-types:', '') #ADVA @@ -61,119 +54,119 @@ def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: ni_type.text = ni_type.text.replace('idx:', '') #CISCO add_value_from_tag(network_instance, 'type', ni_type) - ni_router_id = xml_network_instance.find('ocni:config/ocni:router-id', namespaces=NAMESPACES) + ni_router_id = find_element(xml_network_instance, 'ni_router_id', device_type, NAMESPACES) add_value_from_tag(network_instance, 'router_id', ni_router_id) - ni_route_dist = xml_network_instance.find('ocni:config/ocni:route-distinguisher', namespaces=NAMESPACES) + ni_route_dist = find_element(xml_network_instance, 'ni_route_distinguisher', device_type, NAMESPACES) add_value_from_tag(network_instance, 'route_distinguisher', ni_route_dist) #ni_address_families = [] #add_value_from_collection(network_instance, 'address_families', ni_address_families) if len(network_instance) == 0: continue - response.append(('/network_instance[{:s}]'.format(network_instance['name']), network_instance)) + response.append((get_resource_key('network_instance', device_type, name=network_instance['name']), network_instance)) - for xml_cpoints in xml_network_instance.xpath(XPATH_NI_PROTOCOLS, namespaces=NAMESPACES): + for xml_cpoints in xml_network_instance.xpath(xpath_ni_protocols, namespaces=NAMESPACES): cpoint = {} add_value_from_tag(cpoint, 'name', ni_name) - connection_point = xml_cpoints.find('ocni:connection-point-id', namespaces=NAMESPACES) + connection_point = find_element(xml_cpoints, 'ni_connection_point_id', device_type, NAMESPACES) add_value_from_tag(cpoint, 'connection_point', connection_point) - for xml_endpoint in xml_cpoints.xpath(XPATH_NI_CPOINTS_ENDPOINT, namespaces=NAMESPACES): - remote_system = xml_endpoint.find('ocni:remote-system', namespaces=NAMESPACES) + for xml_endpoint in xml_cpoints.xpath(xpath_ni_endpoints, namespaces=NAMESPACES): + remote_system = find_element(xml_endpoint, 'ni_remote_system', device_type, NAMESPACES) add_value_from_tag(cpoint, 'remote_system', remote_system) - VC_ID = xml_endpoint.find('ocni:virtual-circuit-identifier', namespaces=NAMESPACES) + VC_ID = find_element(xml_endpoint, 'ni_virtual_circuit_identifier', device_type, NAMESPACES) add_value_from_tag(cpoint, 'VC_ID', VC_ID) - for xml_protocol in xml_network_instance.xpath(XPATH_NI_PROTOCOLS, namespaces=NAMESPACES): + for xml_protocol in xml_network_instance.xpath(xpath_ni_protocols, namespaces=NAMESPACES): #LOGGER.info('xml_protocol = {:s}'.format(str(ET.tostring(xml_protocol)))) protocol = {} add_value_from_tag(protocol, 'name', ni_name) - identifier = xml_protocol.find('ocni:identifier', namespaces=NAMESPACES) - if identifier is None: identifier = xml_protocol.find('ocpt:identifier', namespaces=NAMESPACES) - if identifier is None: identifier = xml_protocol.find('ocpt2:identifier', namespaces=NAMESPACES) + identifier = find_element(xml_protocol, 'ni_protocol_identifier', device_type, NAMESPACES) if identifier is None or identifier.text is None: continue add_value_from_tag(protocol, 'identifier', identifier, cast=lambda s: s.replace('oc-pol-types:', '')) - name = xml_protocol.find('ocni:name', namespaces=NAMESPACES) + name = find_element(xml_protocol, 'ni_protocol_name', device_type, NAMESPACES) add_value_from_tag(protocol, 'protocol_name', name) if protocol['identifier'] == 'BGP': - bgp_as = xml_protocol.find('ocni:bgp/ocni:global/ocni:config/ocni:as', namespaces=NAMESPACES) + bgp_as = find_element(xml_protocol, 'ni_bgp_as', device_type, NAMESPACES) add_value_from_tag(protocol, 'as', bgp_as, cast=int) - bgp_id = xml_protocol.find('ocni:bgp/ocni:global/ocni:config/ocni:router-id', namespaces=NAMESPACES) + bgp_id = find_element(xml_protocol, 'ni_bgp_router_id', device_type, NAMESPACES) add_value_from_tag(protocol, 'router_id', bgp_id) - resource_key = '/network_instance[{:s}]/protocols[{:s}]'.format( - network_instance['name'], protocol['identifier']) + resource_key = get_resource_key('network_instance_protocols', device_type, + name=network_instance['name'], identifier=protocol['identifier']) response.append((resource_key, protocol)) - for xml_table_connection in xml_network_instance.xpath(XPATH_NI_TABLE_CONNECTS, namespaces=NAMESPACES): + for xml_table_connection in xml_network_instance.xpath(xpath_ni_table_connections, namespaces=NAMESPACES): #LOGGER.info('xml_table_connection = {:s}'.format(str(ET.tostring(xml_table_connection)))) table_connection = {} add_value_from_tag(table_connection, 'name', ni_name) - src_protocol = xml_table_connection.find('ocni:src-protocol', namespaces=NAMESPACES) + src_protocol = find_element(xml_table_connection, 'ni_src_protocol', device_type, NAMESPACES) add_value_from_tag(table_connection, 'src_protocol', src_protocol, cast=lambda s: s.replace('oc-pol-types:', '')) - dst_protocol = xml_table_connection.find('ocni:dst-protocol', namespaces=NAMESPACES) + dst_protocol = find_element(xml_table_connection, 'ni_dst_protocol', device_type, NAMESPACES) add_value_from_tag(table_connection, 'dst_protocol', dst_protocol, cast=lambda s: s.replace('oc-pol-types:', '')) - address_family = xml_table_connection.find('ocni:address-family', namespaces=NAMESPACES) + address_family = find_element(xml_table_connection, 'ni_address_family', device_type, NAMESPACES) add_value_from_tag(table_connection, 'address_family', address_family, cast=lambda s: s.replace('oc-types:', '')) - default_import_policy = xml_table_connection.find('ocni:config/ocni:default-import-policy', namespaces=NAMESPACES) + default_import_policy = find_element(xml_table_connection, 'ni_default_import_policy', device_type, NAMESPACES) add_value_from_tag(table_connection, 'default_import_policy', default_import_policy) - resource_key = '/network_instance[{:s}]/table_connections[{:s}][{:s}][{:s}]'.format( - network_instance['name'], table_connection['src_protocol'], table_connection['dst_protocol'], - table_connection['address_family']) + resource_key = get_resource_key('network_instance_table_connections', device_type, + name=network_instance['name'], + src_protocol=table_connection['src_protocol'], + dst_protocol=table_connection['dst_protocol'], + address_family=table_connection['address_family']) response.append((resource_key, table_connection)) - for xml_interface in xml_network_instance.xpath(XPATH_NI_INTERFACE, namespaces=NAMESPACES): + for xml_interface in xml_network_instance.xpath(xpath_ni_interface, namespaces=NAMESPACES): LOGGER.info('xml_interfaces = {:s}'.format(str(ET.tostring(xml_interface)))) interface = {} - name_iface = xml_interface.find('ocni:config/ocni:interface', namespaces=NAMESPACES) + name_iface = find_element(xml_interface, 'ni_interface_name', device_type, NAMESPACES) if name_iface is None or name_iface.text is None: continue add_value_from_tag(interface, 'name_iface', name_iface) - name_subiface = xml_interface.find('ocni:config/ocni:subinterface', namespaces=NAMESPACES) + name_subiface = find_element(xml_interface, 'ni_subinterface_name', device_type, NAMESPACES) add_value_from_tag(interface, 'name_subiface', name_subiface) - resource_key = '/network_instance[{:s}]/interface[{:s}]'.format( - network_instance['name'], interface['name_iface']) + resource_key = get_resource_key('network_instance_interface', device_type, + name=network_instance['name'], interface_name=interface['name_iface']) response.append((resource_key, interface)) - for xml_iip_ap in xml_network_instance.xpath(XPATH_NI_IIP_AP, namespaces=NAMESPACES): + for xml_iip_ap in xml_network_instance.xpath(xpath_ni_apply_policy, namespaces=NAMESPACES): #LOGGER.info('xml_iip_ap = {:s}'.format(str(ET.tostring(xml_iip_ap)))) - for xml_import_policy in xml_iip_ap.xpath(XPATH_NI_IIP_AP_IMPORT, namespaces=NAMESPACES): + for xml_import_policy in xml_iip_ap.xpath(xpath_ni_import_policy, namespaces=NAMESPACES): #LOGGER.info('xml_import_policy = {:s}'.format(str(ET.tostring(xml_import_policy)))) if xml_import_policy.text is None: continue iip_ap = {} add_value_from_tag(iip_ap, 'name', ni_name) add_value_from_tag(iip_ap, 'import_policy', xml_import_policy) - resource_key = '/network_instance[{:s}]/inter_instance_policies[{:s}]'.format( - iip_ap['name'], iip_ap['import_policy']) + resource_key = get_resource_key('network_instance_inter_instance_policies', device_type, + name=iip_ap['name'], policy_name=iip_ap['import_policy']) response.append((resource_key, iip_ap)) - for xml_export_policy in xml_iip_ap.xpath(XPATH_NI_IIP_AP_EXPORT, namespaces=NAMESPACES): + for xml_export_policy in xml_iip_ap.xpath(xpath_ni_export_policy, namespaces=NAMESPACES): #LOGGER.info('xml_export_policy = {:s}'.format(str(ET.tostring(xml_export_policy)))) if xml_export_policy.text is None: continue iip_ap = {} add_value_from_tag(iip_ap, 'name', ni_name) add_value_from_tag(iip_ap, 'export_policy', xml_export_policy) - resource_key = '/network_instance[{:s}]/inter_instance_policies[{:s}]'.format( - iip_ap['name'], iip_ap['export_policy']) + resource_key = get_resource_key('network_instance_inter_instance_policies', device_type, + name=iip_ap['name'], policy_name=iip_ap['export_policy']) response.append((resource_key, iip_ap)) diff --git a/src/device/service/drivers/openconfig/templates/RoutingPolicy.py b/src/device/service/drivers/openconfig/templates/RoutingPolicy.py index eac90ed5121309a154fe9c59e434aa461b96f670..e0f8c34447829b52046bc51c31083e76b7e90e80 100644 --- a/src/device/service/drivers/openconfig/templates/RoutingPolicy.py +++ b/src/device/service/drivers/openconfig/templates/RoutingPolicy.py @@ -16,72 +16,77 @@ import copy, logging, lxml.etree as ET from typing import Any, Dict, List, Tuple from .Namespace import NAMESPACES from .Tools import add_value_from_tag +from inter_device_translation import get_dict_helper +from . import find_element, get_resource_key LOGGER = logging.getLogger(__name__) -XPATH_POLICY_DEFINITIONS = "//ocrp:routing-policy/ocrp:policy-definitions/ocrp:policy-definition" -XPATH_PD_STATEMENTS = ".//ocrp:statements/ocrp:statement" -XPATH_PD_ST_CONDITIONS = ".//ocrp:conditions/ocbp:bgp-conditions/ocbp:match-ext-community-set" -XPATH_PD_ST_ACTIONS = ".//ocrp:actions" - -XPATH_BGP_EXT_COMMUN_SET = "//ocrp:routing-policy/ocrp:defined-sets/ocbp:bgp-defined-sets/" + \ - "ocbp:ext-community-sets/ocbp:ext-community-set" - -def parse(xml_data : ET.Element) -> List[Tuple[str, Dict[str, Any]]]: +def parse(xml_data : ET.Element, device_type : str = None) -> List[Tuple[str, Dict[str, Any]]]: + # Get device-specific paths + dict_helper = get_dict_helper(device_type) + xpath_policy_definitions = "//" + dict_helper.get_path('routing_policy_definitions') + xpath_pd_statements = ".//" + dict_helper.get_path('pd_statements') + xpath_pd_conditions = ".//" + dict_helper.get_path('pd_conditions') + xpath_pd_actions = ".//" + dict_helper.get_path('pd_actions') + xpath_bgp_ext_community_set = "//" + dict_helper.get_path('bgp_ext_community_set') #LOGGER.info('[RoutePolicy] xml_data = {:s}'.format(str(ET.tostring(xml_data)))) response = [] - for xml_policy_definition in xml_data.xpath(XPATH_POLICY_DEFINITIONS, namespaces=NAMESPACES): + for xml_policy_definition in xml_data.xpath(xpath_policy_definitions, namespaces=NAMESPACES): #LOGGER.info('xml_policy_definition = {:s}'.format(str(ET.tostring(xml_policy_definition)))) policy_definition = {} statement_name = '' - policy_name = xml_policy_definition.find('ocrp:name', namespaces=NAMESPACES) + policy_name = find_element(xml_policy_definition, 'rp_policy_name', device_type, NAMESPACES) if policy_name is None or policy_name.text is None: continue add_value_from_tag(policy_definition, 'policy_name', policy_name) - resource_key = '/routing_policy/policy_definition[{:s}]'.format(policy_definition['policy_name']) + resource_key = get_resource_key('routing_policy_definition', device_type, + name=policy_definition['policy_name']) response.append((resource_key, copy.deepcopy(policy_definition))) - for xml_statement in xml_policy_definition.xpath(XPATH_PD_STATEMENTS, namespaces=NAMESPACES): - statement_name = xml_statement.find('ocrp:name', namespaces=NAMESPACES) - if len(statement_name) != 0: #FIX: In case there is a route policy defined without a statement name + for xml_statement in xml_policy_definition.xpath(xpath_pd_statements, namespaces=NAMESPACES): + statement_name = find_element(xml_statement, 'rp_statement_name', device_type, NAMESPACES) + if statement_name is not None and len(statement_name) != 0: #FIX: In case there is a route policy defined without a statement name add_value_from_tag(policy_definition, 'statement_name', statement_name) - for xml_condition in xml_statement.xpath(XPATH_PD_ST_CONDITIONS, namespaces=NAMESPACES): - ext_community_set_name = xml_condition.find('ocbp:config/ocbp:ext-community-set', namespaces=NAMESPACES) + for xml_condition in xml_statement.xpath(xpath_pd_conditions, namespaces=NAMESPACES): + ext_community_set_name = find_element(xml_condition, 'rp_ext_community_set', device_type, NAMESPACES) add_value_from_tag(policy_definition, 'ext_community_set_name', ext_community_set_name) - match_set_options = xml_condition.find('ocbp:config/ocbp:match-set-options', namespaces=NAMESPACES) + match_set_options = find_element(xml_condition, 'rp_match_set_options', device_type, NAMESPACES) add_value_from_tag(policy_definition, 'match_set_options', match_set_options) - for xml_action in xml_statement.xpath(XPATH_PD_ST_ACTIONS, namespaces=NAMESPACES): - policy_result = xml_action.find('ocbp:config/ocbp:policy-result', namespaces=NAMESPACES) + for xml_action in xml_statement.xpath(xpath_pd_actions, namespaces=NAMESPACES): + policy_result = find_element(xml_action, 'rp_policy_result', device_type, NAMESPACES) add_value_from_tag(policy_definition, 'policy_result', policy_result) if len(statement_name) != 0: #FIX: In case there is a route policy defined without a statement name - resource_key = '/routing_policy/policy_definition[{:s}]/statement[{:s}]'.format( - policy_definition['policy_name'], policy_definition['statement_name']) + resource_key = get_resource_key('routing_policy_statement', device_type, + name=policy_definition['policy_name'], + statement_name=policy_definition['statement_name']) response.append((resource_key, copy.deepcopy(policy_definition))) - for xml_bgp_ext_community_set in xml_data.xpath(XPATH_BGP_EXT_COMMUN_SET, namespaces=NAMESPACES): + for xml_bgp_ext_community_set in xml_data.xpath(xpath_bgp_ext_community_set, namespaces=NAMESPACES): #LOGGER.info('xml_bgp_ext_community_set = {:s}'.format(str(ET.tostring(xml_bgp_ext_community_set)))) bgp_ext_community_set = {} - ext_community_set_name = xml_bgp_ext_community_set.find('ocbp:ext-community-set-name', namespaces=NAMESPACES) + ext_community_set_name = find_element(xml_bgp_ext_community_set, 'rp_ext_community_set_name', device_type, NAMESPACES) if ext_community_set_name is None or ext_community_set_name.text is None: continue add_value_from_tag(bgp_ext_community_set, 'ext_community_set_name', ext_community_set_name) - resource_key = '/routing_policy/bgp_defined_set[{:s}]'.format(bgp_ext_community_set['ext_community_set_name']) + resource_key = get_resource_key('routing_policy_bgp_defined_set', device_type, + name=bgp_ext_community_set['ext_community_set_name']) response.append((resource_key, copy.deepcopy(bgp_ext_community_set))) - ext_community_member = xml_bgp_ext_community_set.find('ocbp:config/ocbp:ext-community-member', namespaces=NAMESPACES) + ext_community_member = find_element(xml_bgp_ext_community_set, 'rp_ext_community_member', device_type, NAMESPACES) if ext_community_member is not None and ext_community_member.text is not None: add_value_from_tag(bgp_ext_community_set, 'ext_community_member', ext_community_member) - resource_key = '/routing_policy/bgp_defined_set[{:s}][{:s}]'.format( - bgp_ext_community_set['ext_community_set_name'], bgp_ext_community_set['ext_community_member']) + resource_key = get_resource_key('routing_policy_bgp_defined_set_member', device_type, + name=bgp_ext_community_set['ext_community_set_name'], + member=bgp_ext_community_set['ext_community_member']) response.append((resource_key, copy.deepcopy(bgp_ext_community_set))) return response diff --git a/src/device/service/drivers/openconfig/templates/__init__.py b/src/device/service/drivers/openconfig/templates/__init__.py index 47559efda07a08e9e56a980436d7dd1470556ecf..0f03f795cf6d36f3366ba814af9289063f6c9fe6 100644 --- a/src/device/service/drivers/openconfig/templates/__init__.py +++ b/src/device/service/drivers/openconfig/templates/__init__.py @@ -21,14 +21,7 @@ import paramiko from .Tools import generate_templates from device.service.driver_api._Driver import ( RESOURCE_ENDPOINTS, RESOURCE_INTERFACES, RESOURCE_NETWORK_INSTANCES, RESOURCE_ROUTING_POLICIES, RESOURCE_ACL, RESOURCE_INVENTORY) -from .EndPoints import parse as parse_endpoints -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 -from .Inventory import parse as parse_inventory -from .acl.acl_adapter import acl_cr_to_dict -from .acl.acl_adapter_ipinfusion_proprietary import acl_cr_to_dict_ipinfusion_proprietary +from inter_device_translation import get_dict_helper LOGGER = logging.getLogger(__name__) @@ -50,6 +43,46 @@ RESOURCE_KEY_MAPPINGS = { RESOURCE_ACL : 'acl', } +RESOURCE_PARSERS = None # will be initialized after dependent imports + +LOGGER = logging.getLogger(__name__) +RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]') +RE_REMOVE_FILTERS_2 = re.compile(r'\/[a-z]+:') +EMPTY_CONFIG = '' +EMPTY_FILTER = '' + +def get_dict_object(object_name: str, device_type: str, plural: bool = False) -> str: + dict_helper = get_dict_helper('oc' if device_type is None else device_type) + return dict_helper.get_object(object_name, plural=plural) + +def find_element(xml_element, element_name: str, device_type: str = None, namespaces: dict = None): + dict_helper = get_dict_helper(device_type) + namespace, path = dict_helper.get_element(element_name) + + if namespaces is None: + namespaces = {} + + return xml_element.find(f'{namespace}:{path}', namespaces=namespaces) + +def get_resource_key(resource_key_name: str, device_type: str = None, **kwargs) -> str: + dict_helper = get_dict_helper(device_type) + return dict_helper.get_resource_key(resource_key_name, **kwargs) + +# Create Jinja2 environment with custom filter +JINJA_ENV = Environment(loader=PackageLoader('device.service.drivers.openconfig'), autoescape=select_autoescape()) +JINJA_ENV.filters['dict_object'] = get_dict_object + + + +from .EndPoints import parse as parse_endpoints +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 +from .Inventory import parse as parse_inventory +from .acl.acl_adapter import acl_cr_to_dict +from .acl.acl_adapter_ipinfusion_proprietary import acl_cr_to_dict_ipinfusion_proprietary + RESOURCE_PARSERS = { 'inventory' : parse_inventory, 'component' : parse_endpoints, @@ -59,31 +92,23 @@ RESOURCE_PARSERS = { 'interfaces/interface/state/counters': parse_counters, 'acl' : parse_acl, } - -LOGGER = logging.getLogger(__name__) -RE_REMOVE_FILTERS = re.compile(r'\[[^\]]+\]') -RE_REMOVE_FILTERS_2 = re.compile(r'\/[a-z]+:') -EMPTY_CONFIG = '' -EMPTY_FILTER = '' -JINJA_ENV = Environment(loader=PackageLoader('device.service.drivers.openconfig'), autoescape=select_autoescape()) - -def get_filter(resource_key : str): +def get_filter(resource_key : str, device_type: str = None): resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key) resource_key = RE_REMOVE_FILTERS.sub('', resource_key) resource_key = RE_REMOVE_FILTERS_2.sub('/', resource_key) resource_key = resource_key.replace('//', '') template_name = '{:s}/get.xml'.format(resource_key) template = JINJA_ENV.get_template(template_name) - return '{:s}'.format(template.render().strip()) + return '{:s}'.format(template.render(device_type=device_type).strip()) -def parse(resource_key : str, xml_data : ET.Element): +def parse(resource_key : str, xml_data : ET.Element, device_type : str = None): resource_key = RESOURCE_KEY_MAPPINGS.get(resource_key, resource_key) resource_key = RE_REMOVE_FILTERS.sub('', resource_key) resource_key = RE_REMOVE_FILTERS_2.sub('/', resource_key) resource_key = resource_key.replace('//', '') parser = RESOURCE_PARSERS.get(resource_key) if parser is None: return [(resource_key, xml_data)] - return parser(xml_data) + return parser(xml_data, device_type) """ # Method Name: compose_config @@ -104,7 +129,7 @@ def parse(resource_key : str, xml_data : ET.Element): """ def compose_config( # template generation - resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None, message_renderer = str + resource_key : str, resource_value : str, delete : bool = False, vendor : Optional[str] = None, message_renderer = str, device_type : Optional[str] = None ) -> str: if (message_renderer == "pyangbind"): @@ -146,7 +171,7 @@ def compose_config( # template generation return [ '{:s}'.format( - template.render(**data, operation=operation, vendor=vendor).strip()) + template.render(**data, device_type=device_type, operation=operation, vendor=vendor).strip()) for template in templates ] diff --git a/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml b/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml index b070b305a505890c51f3751d2b83eb415ae4aa43..2679d5e9c0562bfa4ebd32862474674410832b7f 100644 --- a/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml +++ b/src/device/service/drivers/openconfig/templates/acl/interfaces/egress/edit_config.xml @@ -1,6 +1,6 @@ - - + <{{ 'interfaces' | dict_object(device_type, plural=True) }}> + <{{ 'interfaces' | dict_object(device_type) {% if operation is defined %}{% if all is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %} {% endif %}> {{id}} {{id}} @@ -8,7 +8,7 @@ {% if interface is defined %} - {{interface}} + <{{ 'interfaces' | dict_object(device_type) }}>{{interface}} {% if subinterface is defined %}{{subinterface}}{% endif%} @@ -25,6 +25,6 @@ {% endif%} - - + + diff --git a/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml index d1f18efb26bc1316354c2bb26623cb36f7dc0be6..950f98b1c1b579bc6f44508a80331c44cc10f240 100644 --- a/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml +++ b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config.xml @@ -1,6 +1,6 @@ - - + <{{ 'interfaces' | dict_object(device_type, plural=True) }}> + <{{ 'interfaces' | dict_object(device_type) {% if operation is defined %}{% if all is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %} {% endif %}> {{id}} {{id}} @@ -8,7 +8,7 @@ {% if interface is defined %} - {{interface}} + <{{ 'interfaces' | dict_object(device_type) }}>{{interface}} {% if subinterface is defined %}{{subinterface}}{% endif%} @@ -25,6 +25,6 @@ {% endif%} - - + + diff --git a/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config_ipinfusion_proprietary.xml b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config_ipinfusion_proprietary.xml index 6e502154f16a7a9d4ce0afc0c49ab96b3a2bd979..a8efd9e33b5310673b51d141a063490b2fcae0e4 100644 --- a/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config_ipinfusion_proprietary.xml +++ b/src/device/service/drivers/openconfig/templates/acl/interfaces/ingress/edit_config_ipinfusion_proprietary.xml @@ -1,6 +1,6 @@ - - + <{{ 'interfaces' | dict_object(device_type, plural=True) }}> + <{{ 'interfaces' | dict_object(device_type) }}> {{interface}} {{interface}} @@ -21,6 +21,6 @@ - - + + \ No newline at end of file diff --git a/src/device/service/drivers/openconfig/templates/component/get.xml b/src/device/service/drivers/openconfig/templates/component/get.xml index aa25ed1e3b11e0c324b361eb52d064dac87a64c5..dd7cff27aea3f5da8bb19f35e26f221ea9d2aa45 100644 --- a/src/device/service/drivers/openconfig/templates/component/get.xml +++ b/src/device/service/drivers/openconfig/templates/component/get.xml @@ -1,3 +1,3 @@ - - - +<{{ 'components' | dict_object(device_type, plural=True) }}> + <{{ 'components' | dict_object(device_type) }}/> + \ No newline at end of file diff --git a/src/device/service/drivers/openconfig/templates/interface/get.xml b/src/device/service/drivers/openconfig/templates/interface/get.xml index c0867655bd325ee9c3cdd74077ac905e36808d5f..ab90a905dcdd16d9ec5a7b317069f6aa881f2c12 100644 --- a/src/device/service/drivers/openconfig/templates/interface/get.xml +++ b/src/device/service/drivers/openconfig/templates/interface/get.xml @@ -1,3 +1,3 @@ - - - +<{{ 'interfaces' | dict_object(device_type, plural=True) }}> + <{{ 'interfaces' | dict_object(device_type) }}/> + \ No newline at end of file diff --git a/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml index e926796d039d54e30f6ba13eb5eb66bcec079c08..cf6fae7e6f62e3e2a80fb2b09df4c1edd2efcec7 100644 --- a/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml +++ b/src/device/service/drivers/openconfig/templates/network_instance/interface/edit_config.xml @@ -5,15 +5,15 @@ {{name}} oc-ni-types:{{type}} - - + <{{ 'interfaces' | dict_object(device_type, plural=True) }}> + <{{ 'interfaces' | dict_object(device_type){% if operation is defined %} xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" nc:operation="{{operation}}"{% endif %}> {{id}} {{id}} - {{interface}} + <{{ 'interfaces' | dict_object(device_type) }}>{{interface}} {{subinterface}} - - + + diff --git a/src/inter_device_translation/__init__.py b/src/inter_device_translation/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..c1a77c75bffc837668e4e5bce238712923ebf99c --- /dev/null +++ b/src/inter_device_translation/__init__.py @@ -0,0 +1,121 @@ +import yaml +import os + + +# Get the directory where this module is located +module_dir = os.path.dirname(os.path.abspath(__file__)) +config_path = os.path.join(module_dir, 'config', 'config.yml') + +with open(config_path) as cfg: + config : dict = yaml.safe_load(cfg) + +dict_name = config.get('name') +dict_default = config.get('default') + + +class DictHelper: + def __init__(self, file): + self.file = file + + def _read(self) -> dict: + with open(self.file) as cfg: + return yaml.safe_load(cfg) + + def get_object(self, name, plural=False) -> str: + config_data = self._read() + if name not in config_data.get('objects', {}): + raise KeyError(f"Object '{name}' not found in configuration") + return config_data['objects'][name].get('plural' if plural else 'singular') + + def get_namespaces(self, name) -> str: + return self._read().get('namespaces', {}).get(name) + + def get_path(self, key, **kwargs) -> str: + path_details = self._read().get('paths', {}).get(key) + if not path_details: + raise KeyError(f"Path '{key}' not found in configuration") + + path : str = path_details.get('path') + namespace = path_details.get('namespace') + + # Format the path with provided parameters + if kwargs: + path = path.format(**kwargs) + + if namespace is None: + return path + + path_segments = path.split('/') + # Only segments without explicit namespace prefixes require one + segments_requiring_ns = [s for s in path_segments if len(s) > 1 and ':' not in s] + + if isinstance(namespace, list): + if len(namespace) != len(segments_requiring_ns): + raise Exception(f'Number of namespaces do not match the specified path : {path}') + namespace_list = namespace + elif isinstance(namespace, str): + namespace_list = [namespace for _ in range(len(segments_requiring_ns))] + else: + namespace_list = [] + + ns_i = 0 + processed_segments = [] + for s in path_segments: + if len(s) > 1: + if ':' in s: + # Segment already includes a namespace prefix; leave as is + processed_segments.append(s) + else: + ns = namespace_list[ns_i] if ns_i < len(namespace_list) else None + processed_segments.append(f'{ns}:{s}' if ns else s) + ns_i += 1 + else: + processed_segments.append(s) + + return '/'.join(processed_segments) + + def get_element(self, name): + """ + Get element namespace and path for XML element lookups. + + Args: + name: The name of the element to look up + + Returns: + Tuple of (namespace, path) for the element + """ + element_details = self._read().get('elements', {}).get(name) + if not element_details: + raise KeyError(f"Element '{name}' not found in configuration") + + namespace = element_details.get('namespace') + path = element_details.get('path') + + return namespace, path + + def get_resource_key(self, key, **kwargs) -> str: + """ + Get device-specific resource key path. + + Args: + name: The resource key name to look up + **kwargs: Parameters to format into the resource key path + + Returns: + Formatted resource key path + """ + resource_key_details = self._read().get('resource_keys', {}).get(key) + if not resource_key_details: + raise KeyError(f"Resource key '{key}' not found in configuration") + + path = resource_key_details.get('path') + if kwargs: + path = path.format(**kwargs) + + return path + + +def get_dict_helper(dict_type = None) -> DictHelper: + if dict_type is None: dict_type = dict_default + config_file = os.path.join(module_dir, 'config', f'{dict_name}.{dict_type}.yml') + return DictHelper(config_file) \ No newline at end of file diff --git a/src/inter_device_translation/config/config.yml b/src/inter_device_translation/config/config.yml new file mode 100644 index 0000000000000000000000000000000000000000..37f7fb1fe36346ab0986897b017a30f65bcde803 --- /dev/null +++ b/src/inter_device_translation/config/config.yml @@ -0,0 +1,2 @@ +name: dict +default: oc \ No newline at end of file diff --git a/src/inter_device_translation/config/dict.ipi.yml b/src/inter_device_translation/config/dict.ipi.yml new file mode 100644 index 0000000000000000000000000000000000000000..654e78294875f1830dc8feb9295023953cc15765 --- /dev/null +++ b/src/inter_device_translation/config/dict.ipi.yml @@ -0,0 +1,460 @@ +namespaces: + interfaces: ipii + interfaces_ip: ipiiip + +objects: + components: + singular: interface + plural: interfaces + interfaces: + singular: interface + plural: interfaces + +paths: + component_type: + namespace: ipiie + path: extended/state/hardware-type + ports: + namespace: ipii + path: interfaces/interface + components: + namespace: ipii + path: interfaces/interface + interface_counters: + namespace: ipii + path: interfaces/interface[name='{interface_name}']/state/counters/{counter_name} + interfaces: + namespace: ipii + path: interfaces/interface + subinterfaces: + namespace: ipii + path: subinterfaces/subinterface + ipv4_addresses: + namespace: ipiiip + path: ipv4/addresses/address + ipv6_addresses: + namespace: ipiiip + path: ipv6/addresses/address + acl_set: + namespace: ipiacl + path: acl/acl-sets/acl-set + acl_entry: + namespace: ipiacl + path: acl-entries/acl-entry + acl_ipv4: + namespace: ipiacl + path: ipv4/config + acl_transport: + namespace: ipiacl + path: transport/config + acl_actions: + namespace: ipiacl + path: actions/config + acl_interface: + namespace: ipiacl + path: acl/interfaces/interface + acl_ingress: + namespace: ipiacl + path: ingress-acl-sets/ingress-acl-set + acl_egress: + namespace: ipiacl + path: egress-acl-sets/egress-acl-set + network_instances: + namespace: ipini + path: network-instances/network-instance + ni_protocols: + namespace: ipini + path: protocols/protocol + ni_table_connections: + namespace: ipini + path: table-connections/table-connection + ni_interface: + namespace: ipini + path: interfaces/interface + ni_apply_policy: + namespace: ipini + path: inter-instance-policies/apply-policy + ni_import_policy: + namespace: ipini + path: config/import-policy + ni_export_policy: + namespace: ipini + path: config/export-policy + ni_connection_points: + namespace: ipini + path: connection-points/connection-point + ni_endpoints: + namespace: ipini + path: endpoints/endpoint/remote/config + routing_policy_definitions: + namespace: ipirp + path: routing-policy/policy-definitions/policy-definition + pd_statements: + namespace: ipirp + path: statements/statement + pd_conditions: + namespace: ipirp + path: conditions/ipibp:bgp-conditions/ipibp:match-ext-community-set + pd_actions: + namespace: ipirp + path: actions + bgp_ext_community_set: + namespace: ipirp + path: routing-policy/defined-sets/ipibp:bgp-defined-sets/ipibp:ext-community-sets/ipibp:ext-community-set + interface_counters_path: + namespace: ipii + path: /ipinfusion-interfaces:interfaces/interface/state/counters + network_instance_interfaces: + namespace: ipini + path: /ipinfusion-network-instance:network-instances/network-instance[name={name}]/interfaces + network_instance_protocols: + namespace: ipini + path: /ipinfusion-network-instance:network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}] + network_instance_static_routes: + namespace: ipini + path: /ipinfusion-network-instance:network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}]/static-routes/static[prefix={prefix}] + network_instance_interface: + namespace: ipini + path: /ipinfusion-network-instances/network-instance[name={name}]/interfaces/interface[id={interface_id}] + network_instance_protocol: + namespace: ipini + path: /ipinfusion-network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}] + network_instance_static_route: + namespace: ipini + path: /ipinfusion-network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}]/static-routes/static[prefix={prefix}] + interface_subinterface: + namespace: ipii + path: /ipinfusion-interfaces/interface[name={name}]/subinterfaces/subinterface[index={index}] + +elements: + interface_name: + namespace: ipii + path: name + interface_type: + namespace: ipii + path: config/type + interface_state_type: + namespace: ipii + path: state/type + interface_mtu: + namespace: ipii + path: config/mtu + interface_description: + namespace: ipii + path: config/description + interface_counters_in_pkts: + namespace: ipii + path: state/counters/in-pkts + interface_counters_in_octets: + namespace: ipii + path: state/counters/in-octets + interface_counters_in_errors: + namespace: ipii + path: state/counters/in-errors + interface_counters_out_octets: + namespace: ipii + path: state/counters/out-octets + interface_counters_out_pkts: + namespace: ipii + path: state/counters/out-pkts + interface_counters_out_errors: + namespace: ipii + path: state/counters/out-errors + interface_counters_out_discards: + namespace: ipii + path: state/counters/out-discards + subinterface_index: + namespace: ipii + path: index + subinterface_vlan: + namespace: ipiv + path: vlan/match/single-tagged/config/vlan-id + ipv4_address: + namespace: ipiiip + path: state/ip + ipv4_prefix: + namespace: ipiiip + path: state/prefix-length + ipv6_address: + namespace: ipiiip + path: state/ip + ipv6_prefix: + namespace: ipiiip + path: state/prefix-length + component_name: + namespace: ipii + path: name + component_type: + namespace: ipii + path: state/type + component_description: + namespace: ipii + path: state/description + component_location: + namespace: ipii + path: state/location + component_id: + namespace: ipii + path: state/id + component_empty: + namespace: ipii + path: state/empty + component_parent: + namespace: ipii + path: state/parent + component_hardware_version: + namespace: ipii + path: state/hardware-version + component_firmware_version: + namespace: ipii + path: state/firmware-version + component_software_version: + namespace: ipii + path: state/software-version + component_serial: + namespace: ipii + path: state/serial-no + component_mfg_name: + namespace: ipii + path: state/mfg-name + component_model_name: + namespace: ipii + path: state/model-name + component_part_no: + namespace: ipii + path: state/part-no + component_removable: + namespace: ipii + path: state/removable + component_replaceable: + namespace: ipii + path: state/replaceable + component_oper_status: + namespace: ipii + path: state/oper-status + acl_name: + namespace: ipiacl + path: name + acl_type: + namespace: ipiacl + path: type + acl_sequence_id: + namespace: ipiacl + path: sequence-id + acl_source_address: + namespace: ipiacl + path: source-address + acl_destination_address: + namespace: ipiacl + path: destination-address + acl_protocol: + namespace: ipiacl + path: protocol + acl_dscp: + namespace: ipiacl + path: dscp + acl_hop_limit: + namespace: ipiacl + path: hop-limit + acl_source_port: + namespace: ipiacl + path: source-port + acl_destination_port: + namespace: ipiacl + path: destination-port + acl_tcp_flags: + namespace: ipiacl + path: tcp-flags + acl_forwarding_action: + namespace: ipiacl + path: forwarding-action + acl_log_action: + namespace: ipiacl + path: log-action + acl_interface_id: + namespace: ipiacl + path: id + acl_set_name_ingress: + namespace: ipiacl + path: set-name-ingress + acl_type_ingress: + namespace: ipiacl + path: type-ingress + acl_set_name_egress: + namespace: ipiacl + path: set-name-egress + acl_type_egress: + namespace: ipiacl + path: type-egress + ni_name: + namespace: ipini + path: name + ni_type: + namespace: ipini + path: config/type + ni_router_id: + namespace: ipini + path: config/router-id + ni_route_distinguisher: + namespace: ipini + path: config/route-distinguisher + ni_connection_point_id: + namespace: ipini + path: connection-point-id + ni_remote_system: + namespace: ipini + path: remote-system + ni_virtual_circuit_identifier: + namespace: ipini + path: virtual-circuit-identifier + ni_protocol_identifier: + namespace: ipini + path: identifier + ni_protocol_name: + namespace: ipini + path: name + ni_bgp_as: + namespace: ipini + path: bgp/global/config/as + ni_bgp_router_id: + namespace: ipini + path: bgp/global/config/router-id + ni_src_protocol: + namespace: ipini + path: src-protocol + ni_dst_protocol: + namespace: ipini + path: dst-protocol + ni_address_family: + namespace: ipini + path: address-family + ni_default_import_policy: + namespace: ipini + path: config/default-import-policy + ni_interface_name: + namespace: ipini + path: config/interface + ni_subinterface_name: + namespace: ipini + path: config/subinterface + rp_policy_name: + namespace: ipirp + path: name + rp_statement_name: + namespace: ipirp + path: name + rp_ext_community_set: + namespace: ipibp + path: config/ext-community-set + rp_match_set_options: + namespace: ipibp + path: config/match-set-options + rp_policy_result: + namespace: ipibp + path: config/policy-result + rp_ext_community_set_name: + namespace: ipibp + path: ext-community-set-name + rp_ext_community_member: + namespace: ipibp + path: config/ext-community-member + inv_component_name: + namespace: ipii + path: name + inv_component_description: + namespace: ipii + path: state/description + inv_component_location: + namespace: ipii + path: state/location + inv_component_id: + namespace: ipii + path: state/id + inv_component_type: + namespace: ipii + path: state/type + inv_component_empty: + namespace: ipii + path: state/empty + inv_component_parent: + namespace: ipii + path: state/parent + inv_component_hardware_version: + namespace: ipii + path: state/hardware-version + inv_component_firmware_version: + namespace: ipii + path: state/firmware-version + inv_component_software_version: + namespace: ipii + path: state/software-version + inv_component_serial: + namespace: ipii + path: state/serial-no + inv_component_mfg_name: + namespace: ipii + path: state/mfg-name + inv_component_removable: + namespace: ipii + path: state/removable + inv_component_mfg_date: + namespace: ipii + path: state/mfg-date + inv_transceiver_serial: + namespace: ipitr + path: transceiver/state/serial-no + inv_transceiver_present: + namespace: ipitr + path: transceiver/state/present + inv_transceiver_vendor: + namespace: ipitr + path: transceiver/state/vendor + inv_transceiver_connector: + namespace: ipitr + path: transceiver/state/connector-type + inv_transceiver_form: + namespace: ipitr + path: transceiver/state/form-factor + ep_component_type: + namespace: ipii + path: state/type + ep_component_name: + namespace: ipii + path: name + ep_port_channel_speed: + namespace: ipipp + path: port/breakout-mode/state/channel-speed + +resource_keys: + network_instance: + path: /network_instance[{name}] + network_instance_protocols: + path: /network_instance[{name}]/protocols[{identifier}] + network_instance_table_connections: + path: /network_instance[{name}]/table_connections[{src_protocol}][{dst_protocol}][{address_family}] + network_instance_interface: + path: /network_instance[{name}]/interface[{interface_name}] + network_instance_inter_instance_policies: + path: /network_instance[{name}]/inter_instance_policies[{policy_name}] + acl_set_entry: + path: /acl/acl-set[{name}][{type}]/acl-entry[{sequence_id}] + acl_interfaces_ingress: + path: /acl/interfaces/ingress[{name}][{type}] + acl_interfaces_egress: + path: /acl/interfaces/egress[{name}][{type}] + interface_subinterface: + path: /interface[{name}]/subinterface[{index}] + routing_policy_definition: + path: /routing_policy/policy_definition[{name}] + routing_policy_statement: + path: /routing_policy/policy_definition[{name}]/statement[{statement_name}] + routing_policy_bgp_defined_set: + path: /routing_policy/bgp_defined_set[{name}] + routing_policy_bgp_defined_set_member: + path: /routing_policy/bgp_defined_set[{name}][{member}] + inventory_component: + path: /inventory[{name}] + endpoints_endpoint: + path: /endpoints/endpoint[{uuid}] + interface: + path: /interface[{name}] \ No newline at end of file diff --git a/src/inter_device_translation/config/dict.oc.yml b/src/inter_device_translation/config/dict.oc.yml new file mode 100644 index 0000000000000000000000000000000000000000..48e2fc250f634f91cf26b567751fab1755d86639 --- /dev/null +++ b/src/inter_device_translation/config/dict.oc.yml @@ -0,0 +1,460 @@ +namespaces: + interfaces: oci + interfaces_ip: ociip + +objects: + components: + singular: component + plural: components + interfaces: + singular: interface + plural: interfaces + +paths: + component_type: + namespace: ocpp + path: port/breakout-mode/state/channel-speed + ports: + namespace: ocp + path: components/component + components: + namespace: ocp + path: components/component + interface_counters: + namespace: oci + path: interfaces/interface[name='{interface_name}']/state/counters/{counter_name} + interfaces: + namespace: oci + path: interfaces/interface + subinterfaces: + namespace: oci + path: subinterfaces/subinterface + ipv4_addresses: + namespace: ociip + path: ipv4/addresses/address + ipv6_addresses: + namespace: ociip + path: ipv6/addresses/address + acl_set: + namespace: ocacl + path: acl/acl-sets/acl-set + acl_entry: + namespace: ocacl + path: acl-entries/acl-entry + acl_ipv4: + namespace: ocacl + path: ipv4/config + acl_transport: + namespace: ocacl + path: transport/config + acl_actions: + namespace: ocacl + path: actions/config + acl_interface: + namespace: ocacl + path: acl/interfaces/interface + acl_ingress: + namespace: ocacl + path: ingress-acl-sets/ingress-acl-set + acl_egress: + namespace: ocacl + path: egress-acl-sets/egress-acl-set + network_instances: + namespace: ocni + path: network-instances/network-instance + ni_protocols: + namespace: ocni + path: protocols/protocol + ni_table_connections: + namespace: ocni + path: table-connections/table-connection + ni_interface: + namespace: ocni + path: interfaces/interface + ni_apply_policy: + namespace: ocni + path: inter-instance-policies/apply-policy + ni_import_policy: + namespace: ocni + path: config/import-policy + ni_export_policy: + namespace: ocni + path: config/export-policy + ni_connection_points: + namespace: ocni + path: connection-points/connection-point + ni_endpoints: + namespace: ocni + path: endpoints/endpoint/remote/config + routing_policy_definitions: + namespace: ocrp + path: routing-policy/policy-definitions/policy-definition + pd_statements: + namespace: ocrp + path: statements/statement + pd_conditions: + namespace: ocrp + path: conditions/ocbp:bgp-conditions/ocbp:match-ext-community-set + pd_actions: + namespace: ocrp + path: actions + bgp_ext_community_set: + namespace: ocrp + path: routing-policy/defined-sets/ocbp:bgp-defined-sets/ocbp:ext-community-sets/ocbp:ext-community-set + interface_counters_path: + namespace: oci + path: /openconfig-interfaces:interfaces/interface/state/counters + network_instance_interfaces: + namespace: ocni + path: /openconfig-network-instance:network-instances/network-instance[name={name}]/interfaces + network_instance_protocols: + namespace: ocni + path: /openconfig-network-instance:network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}] + network_instance_static_routes: + namespace: ocni + path: /openconfig-network-instance:network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}]/static-routes/static[prefix={prefix}] + network_instance_interface: + namespace: ocni + path: /network-instances/network-instance[name={name}]/interfaces/interface[id={interface_id}] + network_instance_protocol: + namespace: ocni + path: /network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}] + network_instance_static_route: + namespace: ocni + path: /network-instances/network-instance[name={name}]/protocols/protocol[identifier={identifier}][name={protocol_name}]/static-routes/static[prefix={prefix}] + interface_subinterface: + namespace: oci + path: /interfaces/interface[name={name}]/subinterfaces/subinterface[index={index}] + +elements: + interface_name: + namespace: oci + path: name + interface_type: + namespace: oci + path: config/type + interface_state_type: + namespace: oci + path: state/type + interface_mtu: + namespace: oci + path: config/mtu + interface_description: + namespace: oci + path: config/description + interface_counters_in_pkts: + namespace: oci + path: state/counters/in-pkts + interface_counters_in_octets: + namespace: oci + path: state/counters/in-octets + interface_counters_in_errors: + namespace: oci + path: state/counters/in-errors + interface_counters_out_octets: + namespace: oci + path: state/counters/out-octets + interface_counters_out_pkts: + namespace: oci + path: state/counters/out-pkts + interface_counters_out_errors: + namespace: oci + path: state/counters/out-errors + interface_counters_out_discards: + namespace: oci + path: state/counters/out-discards + subinterface_index: + namespace: oci + path: index + subinterface_vlan: + namespace: ocv + path: vlan/match/single-tagged/config/vlan-id + ipv4_address: + namespace: ociip + path: state/ip + ipv4_prefix: + namespace: ociip + path: state/prefix-length + ipv6_address: + namespace: ociip + path: state/ip + ipv6_prefix: + namespace: ociip + path: state/prefix-length + component_name: + namespace: ocp + path: name + component_type: + namespace: ocp + path: state/type + component_description: + namespace: ocp + path: state/description + component_location: + namespace: ocp + path: state/location + component_id: + namespace: ocp + path: state/id + component_empty: + namespace: ocp + path: state/empty + component_parent: + namespace: ocp + path: state/parent + component_hardware_version: + namespace: ocp + path: state/hardware-version + component_firmware_version: + namespace: ocp + path: state/firmware-version + component_software_version: + namespace: ocp + path: state/software-version + component_serial: + namespace: ocp + path: state/serial-no + component_mfg_name: + namespace: ocp + path: state/mfg-name + component_model_name: + namespace: ocp + path: state/model-name + component_part_no: + namespace: ocp + path: state/part-no + component_removable: + namespace: ocp + path: state/removable + component_replaceable: + namespace: ocp + path: state/replaceable + component_oper_status: + namespace: ocp + path: state/oper-status + acl_name: + namespace: ocacl + path: name + acl_type: + namespace: ocacl + path: type + acl_sequence_id: + namespace: ocacl + path: sequence-id + acl_source_address: + namespace: ocacl + path: source-address + acl_destination_address: + namespace: ocacl + path: destination-address + acl_protocol: + namespace: ocacl + path: protocol + acl_dscp: + namespace: ocacl + path: dscp + acl_hop_limit: + namespace: ocacl + path: hop-limit + acl_source_port: + namespace: ocacl + path: source-port + acl_destination_port: + namespace: ocacl + path: destination-port + acl_tcp_flags: + namespace: ocacl + path: tcp-flags + acl_forwarding_action: + namespace: ocacl + path: forwarding-action + acl_log_action: + namespace: ocacl + path: log-action + acl_interface_id: + namespace: ocacl + path: id + acl_set_name_ingress: + namespace: ocacl + path: set-name-ingress + acl_type_ingress: + namespace: ocacl + path: type-ingress + acl_set_name_egress: + namespace: ocacl + path: set-name-egress + acl_type_egress: + namespace: ocacl + path: type-egress + ni_name: + namespace: ocni + path: name + ni_type: + namespace: ocni + path: config/type + ni_router_id: + namespace: ocni + path: config/router-id + ni_route_distinguisher: + namespace: ocni + path: config/route-distinguisher + ni_connection_point_id: + namespace: ocni + path: connection-point-id + ni_remote_system: + namespace: ocni + path: remote-system + ni_virtual_circuit_identifier: + namespace: ocni + path: virtual-circuit-identifier + ni_protocol_identifier: + namespace: ocni + path: identifier + ni_protocol_name: + namespace: ocni + path: name + ni_bgp_as: + namespace: ocni + path: bgp/global/config/as + ni_bgp_router_id: + namespace: ocni + path: bgp/global/config/router-id + ni_src_protocol: + namespace: ocni + path: src-protocol + ni_dst_protocol: + namespace: ocni + path: dst-protocol + ni_address_family: + namespace: ocni + path: address-family + ni_default_import_policy: + namespace: ocni + path: config/default-import-policy + ni_interface_name: + namespace: ocni + path: config/interface + ni_subinterface_name: + namespace: ocni + path: config/subinterface + rp_policy_name: + namespace: ocrp + path: name + rp_statement_name: + namespace: ocrp + path: name + rp_ext_community_set: + namespace: ocbp + path: config/ext-community-set + rp_match_set_options: + namespace: ocbp + path: config/match-set-options + rp_policy_result: + namespace: ocbp + path: config/policy-result + rp_ext_community_set_name: + namespace: ocbp + path: ext-community-set-name + rp_ext_community_member: + namespace: ocbp + path: config/ext-community-member + inv_component_name: + namespace: ocp + path: name + inv_component_description: + namespace: ocp + path: state/description + inv_component_location: + namespace: ocp + path: state/location + inv_component_id: + namespace: ocp + path: state/id + inv_component_type: + namespace: ocp + path: state/type + inv_component_empty: + namespace: ocp + path: state/empty + inv_component_parent: + namespace: ocp + path: state/parent + inv_component_hardware_version: + namespace: ocp + path: state/hardware-version + inv_component_firmware_version: + namespace: ocp + path: state/firmware-version + inv_component_software_version: + namespace: ocp + path: state/software-version + inv_component_serial: + namespace: ocp + path: state/serial-no + inv_component_mfg_name: + namespace: ocp + path: state/mfg-name + inv_component_removable: + namespace: ocp + path: state/removable + inv_component_mfg_date: + namespace: ocp + path: state/mfg-date + inv_transceiver_serial: + namespace: ocptr + path: transceiver/state/serial-no + inv_transceiver_present: + namespace: ocptr + path: transceiver/state/present + inv_transceiver_vendor: + namespace: ocptr + path: transceiver/state/vendor + inv_transceiver_connector: + namespace: ocptr + path: transceiver/state/connector-type + inv_transceiver_form: + namespace: ocptr + path: transceiver/state/form-factor + ep_component_type: + namespace: ocp + path: state/type + ep_component_name: + namespace: ocp + path: name + ep_port_channel_speed: + namespace: ocpp + path: port/breakout-mode/state/channel-speed + +resource_keys: + network_instance: + path: /network_instance[{name}] + network_instance_protocols: + path: /network_instance[{name}]/protocols[{identifier}] + network_instance_table_connections: + path: /network_instance[{name}]/table_connections[{src_protocol}][{dst_protocol}][{address_family}] + network_instance_interface: + path: /network_instance[{name}]/interface[{interface_name}] + network_instance_inter_instance_policies: + path: /network_instance[{name}]/inter_instance_policies[{policy_name}] + acl_set_entry: + path: /acl/acl-set[{name}][{type}]/acl-entry[{sequence_id}] + acl_interfaces_ingress: + path: /acl/interfaces/ingress[{name}][{type}] + acl_interfaces_egress: + path: /acl/interfaces/egress[{name}][{type}] + interface_subinterface: + path: /interface[{name}]/subinterface[{index}] + routing_policy_definition: + path: /routing_policy/policy_definition[{name}] + routing_policy_statement: + path: /routing_policy/policy_definition[{name}]/statement[{statement_name}] + routing_policy_bgp_defined_set: + path: /routing_policy/bgp_defined_set[{name}] + routing_policy_bgp_defined_set_member: + path: /routing_policy/bgp_defined_set[{name}][{member}] + inventory_component: + path: /inventory[{name}] + endpoints_endpoint: + path: /endpoints/endpoint[{uuid}] + interface: + path: /interface[{name}] \ No newline at end of file diff --git a/src/load_generator/requirements.in b/src/load_generator/requirements.in index a2ee41d8317c5146977ef173654b823f476d2237..72a3d081a866a54fa48f175a8c91994bcea4e7f8 100644 --- a/src/load_generator/requirements.in +++ b/src/load_generator/requirements.in @@ -13,3 +13,4 @@ # limitations under the License. APScheduler>=3.10.4 +pytz