diff --git a/networkapi/api_interface/views.py b/networkapi/api_interface/views.py index 7d6d92c4..c7b1408a 100644 --- a/networkapi/api_interface/views.py +++ b/networkapi/api_interface/views.py @@ -41,6 +41,7 @@ from networkapi.util.decorators import prepare_search from networkapi.util.json_validate import json_validate from networkapi.util.json_validate import raise_json_validate +from networkapi.util.interface_validate import InterfaceOverrideValidator from networkapi.util.geral import create_lock from networkapi.util.geral import destroy_lock from networkapi.util.geral import render_to_json @@ -327,6 +328,10 @@ class InterfaceV3View(CustomAPIView): def get(self, request, *args, **kwargs): """URL: api/v3/interface/""" + log.info('InterfaceV3View GET') + log.info('kwargs: %s', kwargs) + log.info('search: %s', self.search) + if not kwargs.get('obj_ids'): obj_model = facade.get_interface_by_search(self.search) interfaces = obj_model['query_set'] @@ -354,6 +359,8 @@ def get(self, request, *args, **kwargs): only_main_property=only_main_property ) + log.info('get interfaces response: %s', data) + return Response(data, status=status.HTTP_200_OK) @logs_method_apiview @@ -369,8 +376,36 @@ def post(self, request, *args, **kwargs): response = list() interfaces = request.DATA + log.info('InterfaceV3View POST') + log.info('interfaces: %s', interfaces) + log.info('kwargs: %s', kwargs) json_validate(SPECS.get('interface_post')).validate(interfaces) + user_interface_str_list = [] + equipmemnt_interface_str_list = [] + for interface in interfaces.get('interfaces'): + + # User interface input, ex.: + # ex.: eth1, eth1/1, 1, Gi1/5, FF:FF:FF:FF:FF:F, int1, mgmt0, ethernet1/12, .. + interface_input = interface['interface'] + user_interface_str_list.append(interface_input) + + # Equipments from input interface + equipment_id = interface['equipment'] + obj_model = facade.get_interface_by_search( + {'extends_search': [], 'start_record': 0, 'custom_search': equipment_id, 'end_record': 1000, 'asorting_cols': ['id'], 'searchable_columns': ['equipamento__id']} + ) + equipment_list = obj_model['query_set'] + log.debug("equipment_list %s", equipment_list) + for equipment_interface in equipment_list: + equipmemnt_interface_str_list.append(equipment_interface.interface) + + # Validate interface overrinding + InterfaceOverrideValidator().check_overriding( + source_interface_str_list=user_interface_str_list, + target_interface_str_list=equipmemnt_interface_str_list + ) + for i in interfaces.get('interfaces'): try: interface = facade.create_interface(i) diff --git a/networkapi/util/interface_validate.py b/networkapi/util/interface_validate.py new file mode 100644 index 00000000..d045681a --- /dev/null +++ b/networkapi/util/interface_validate.py @@ -0,0 +1,87 @@ +""" +Interface validator module +""" +import re +import logging +from networkapi.api_rest.exceptions import NetworkAPIException + +log = logging.getLogger(__name__) + + +class InterfaceOverrideValidator: + """ + Class responsible to interfaces (or ports) valitions. + """ + + def check_overriding(self, source_interface_str_list, target_interface_str_list): + """ + Public method to check if source interface overides target interfaces. + + Allowed interfaces sample: + source_interface_str_list = ['eth1/1', 'eth3/2'] + target_interface_str_list = ['eth2', 'eth3/1'] + + Prohibited interfaces sample: + source_interface_str_list = ['eth1/1', 'eth3/2'] + target_interface_str_list = ['eth1', 'eth1/1', 'eth3'] + + :param source_interface_str_list str list: String array of interfaces, ex.: ['eth1', 'eth2', 'eth2/1'] + :param target_interface_str_list str list: String array of interfaces, ex.: ['eth2/1/3', 'eth2/1/2/1'] + :return first prohibited interface as False, otherwise, allowed interface as True: + """ + + try: + + log.info('check_overriding START') + log.info('source_interface_str_list: %s', source_interface_str_list) + log.info('target_interface_str_list: %s', target_interface_str_list) + + # Validate + for source_interface_str in source_interface_str_list: + for target_interface_str in target_interface_str_list: + + log.info("Validating '%s' with '%s'", source_interface_str, source_interface_str) + source_interface_array = [int(num) for num in re.findall(r'\d+', source_interface_str)] + target_interface_array = [int(num) for num in re.findall(r'\d+', target_interface_str)] + response = self._is_overriding( + source_list=source_interface_array, + target_list=target_interface_array) + if not response: + raise NetworkAPIException("A interface requisitada '{}' sobrepoe a interface '{}' do equipamento".format( + source_interface_str, target_interface_str + ) + ) + + except Exception as ex: + raise NetworkAPIException(str(ex)) + + def _is_overriding(self, source_list, target_list, lvl=0): + """ + Private method check if source interface overides target interfaces. + The interfaces are represented by array, ex. [1,1] is 'eth1/1'. + + :param source interfaces: Represented array of interfaces, ex.: [1,1] [1,2,1] [2] + :param source interfaces: Represented array of interfaces, ex.: [1] [1,2,3] [4] + :param recursive level control. + :return first prohibited interface as False, otherwise, allowed interface as True: + """ + + try: + # Identical + if source_list == target_list: + log.info('*** PROHIBITED ***') + return False + elif not source_list or not target_list: + log.info('**** PROHIBITED ****') + return False + elif source_list and target_list and source_list[0] == target_list[0]: + return self._is_overriding( + source_list=source_list[1:], + target_list=target_list[1:], + lvl=lvl+1 + ) + else: + log.info('**** ALLOWED ****') + return True + except Exception as ex: + raise NetworkAPIException(str(ex))