From dcfd61ae55db98bca56f778e800e816029905474 Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Tue, 5 Jan 2021 10:24:35 -0300 Subject: [PATCH 1/6] allow to allocate the first and last ip --- networkapi/ip/models.py | 62 +++++++++++------- networkapi/ip/resource/IPv4SaveResource.py | 73 ++++++++++++---------- 2 files changed, 78 insertions(+), 57 deletions(-) diff --git a/networkapi/ip/models.py b/networkapi/ip/models.py index 573ca5ba3..6e7dbcb3e 100644 --- a/networkapi/ip/models.py +++ b/networkapi/ip/models.py @@ -1483,6 +1483,7 @@ def save_ipv4(self, equipment_id, user, net): equipamentoambiente = get_model('equipamento', 'EquipamentoAmbiente') equipamento = get_model('equipamento', 'Equipamento') filterequiptype = get_model('filterequiptype', 'FilterEquipType') + try: already_ip = False @@ -1491,7 +1492,7 @@ def save_ipv4(self, equipment_id, user, net): net4 = IPv4Network( '%d.%d.%d.%d/%d' % (net.oct1, net.oct2, net.oct3, net.oct4, net.block)) - # Find all ips ralated to network + # Find all ips related to network ips = Ip.objects.filter(networkipv4__id=net.id) ip4_object = IPv4Address( @@ -1499,24 +1500,24 @@ def save_ipv4(self, equipment_id, user, net): # Cast all to API class ipsv4 = set( - [IPv4Address('%d.%d.%d.%d' % (ip.oct1, ip.oct2, ip.oct3, ip.oct4)) for ip in ips]) + [IPv4Address('%d.%d.%d.%d' % ( + ip.oct1, ip.oct2, ip.oct3, ip.oct4)) for ip in ips]) flag = False if ip4_object not in ipsv4: if ip4_object in net4: + # allow to allocate the first and last ip + flag = True - # Get configuration - # conf = Configuration.get() - - first_ip_network = int(net4.network) - bcast_ip_network = int(net4.broadcast) - - ipv4_network = int(ip4_object) - - if ipv4_network >= (first_ip_network) and ipv4_network < (bcast_ip_network): - flag = True + # first_ip_network = int(net4.network) + # bcast_ip_network = int(net4.broadcast) + # + # ipv4_network = int(ip4_object) + # + # if bcast_ip_network > ipv4_network >= first_ip_network: + # flag = True else: @@ -1524,9 +1525,12 @@ def save_ipv4(self, equipment_id, user, net): self.oct1, self.oct2, self.oct3, self.oct4, net.id) try: IpEquipamento.get_by_ip(ip_aux.id) - raise IpEquipmentAlreadyAssociation(None, u'Ip %s.%s.%s.%s already has association with an Equipament. Try using the association screen for this Ip.' % ( + raise IpEquipmentAlreadyAssociation( + None, + u'Ip %s.%s.%s.%s already has association with an Equipament. ' + u'Try using the association screen for this Ip.' % ( self.oct1, self.oct2, self.oct3, self.oct4)) - except IpEquipmentNotFoundError, e: + except IpEquipmentNotFoundError: flag = True already_ip = True @@ -1546,8 +1550,8 @@ def save_ipv4(self, equipment_id, user, net): ip_equipment.equipamento = equipment - # # Filter case 2 - Adding new IpEquip for a equip that already have ip in other network with the same range ## - + # Filter case 2 - Adding new IpEquip for a equip that already + # have ip in other network with the same range # Get all IpEquipamento related to this equipment ip_equips = IpEquipamento.objects.filter( equipamento=equipment_id) @@ -1561,22 +1565,30 @@ def save_ipv4(self, equipment_id, user, net): ip_test.networkipv4 != self.networkipv4: # Filter testing - if ip_test.networkipv4.vlan.ambiente.filter is None or self.networkipv4.vlan.ambiente.filter is None: + if ip_test.networkipv4.vlan.ambiente.filter is None \ + or self.networkipv4.vlan.ambiente.filter is None: raise IpRangeAlreadyAssociation( - None, u'Equipment is already associated with another ip with the same ip range.') + None, u'Equipment is already associated with another ' + u'ip with the same ip range.') else: # Test both environment's filters tp_equip_list_one = list() - for fet in filterequiptype.objects.filter(filter=self.networkipv4.vlan.ambiente.filter.id): + for fet in filterequiptype.objects.filter( + filter=self.networkipv4.vlan.ambiente.filter.id): tp_equip_list_one.append(fet.equiptype) tp_equip_list_two = list() - for fet in filterequiptype.objects.filter(filter=ip_test.networkipv4.vlan.ambiente.filter.id): + for fet in filterequiptype.objects.filter( + filter=ip_test.networkipv4.vlan.ambiente.filter.id): tp_equip_list_two.append(fet.equiptype) - if equipment.tipo_equipamento not in tp_equip_list_one or equipment.tipo_equipamento not in tp_equip_list_two: + if equipment.tipo_equipamento not \ + in tp_equip_list_one \ + or equipment.tipo_equipamento not \ + in tp_equip_list_two: raise IpRangeAlreadyAssociation( - None, u'Equipment is already associated with another ip with the same ip range.') + None, u'Equipment is already associated with ' + u'another ip with the same ip range.') # # Filter case 2 - end ## @@ -1593,7 +1605,8 @@ def save_ipv4(self, equipment_id, user, net): pass else: - raise IpNotAvailableError(None, u'Ip %s.%s.%s.%s not available for network %s.' % ( + raise IpNotAvailableError(None, u'Ip %s.%s.%s.%s not available ' + u'for network %s.' % ( self.oct1, self.oct2, self.oct3, self.oct4, net.id)) except IpRangeAlreadyAssociation, e: @@ -1604,7 +1617,8 @@ def save_ipv4(self, equipment_id, user, net): raise InvalidValueError( None, 'ip', u'%s.%s.%s.%s' % (self.oct1, self.oct2, self.oct3, self.oct4)) except IpNotAvailableError, e: - raise IpNotAvailableError(None, u'Ip %s.%s.%s.%s not available for network %s.' % ( + raise IpNotAvailableError(None, u'Ip %s.%s.%s.%s not available for ' + u'network %s.' % ( self.oct1, self.oct2, self.oct3, self.oct4, net.id)) except (IpError, EquipamentoError), e: self.log.error( diff --git a/networkapi/ip/resource/IPv4SaveResource.py b/networkapi/ip/resource/IPv4SaveResource.py index 6dee9f238..fb0208add 100644 --- a/networkapi/ip/resource/IPv4SaveResource.py +++ b/networkapi/ip/resource/IPv4SaveResource.py @@ -96,7 +96,8 @@ def handle_post(self, request, user, *args, **kwargs): # Valid network_ipv4_id if not is_valid_int_greater_zero_param(network_ipv4_id): self.log.error( - u'Parameter network_ipv4_id is invalid. Value: %s.', network_ipv4_id) + u'Parameter network_ipv4_id is invalid. Value: %s.', + network_ipv4_id) raise InvalidValueError( None, 'network_ipv4_id', network_ipv4_id) @@ -107,7 +108,8 @@ def handle_post(self, request, user, *args, **kwargs): # Description can NOT be greater than 100 if description is not None: - if not is_valid_string_maxsize(description, 100) or not is_valid_string_minsize(description, 3): + if not is_valid_string_maxsize(description, 100) \ + or not is_valid_string_minsize(description, 3): self.log.error( u'Parameter description is invalid. Value: %s.', description) raise InvalidValueError(None, 'description', description) @@ -123,25 +125,19 @@ def handle_post(self, request, user, *args, **kwargs): None, u'User does not have permission to perform the operation.') # Business Rules - - # New IP ip = Ip() net = NetworkIPv4.get_by_pk(network_ipv4_id) with distributedlock(LOCK_NETWORK_IPV4 % network_ipv4_id): - # se Houver erro no ip informado para retorna-lo na mensagem ip_error = ip4 - # verificação se foi passado algo errado no ip ip4 = ip4.split('.') - for oct in ip4: - if not is_valid_int_param(oct): + for octs in ip4: + if not is_valid_int_param(octs): raise InvalidValueError(None, 'ip4', ip_error) - # raise IndexError - # Ip passado de forma invalida if len(ip4) is not 4: raise IndexError @@ -166,8 +162,6 @@ def handle_post(self, request, user, *args, **kwargs): listaVlansDoEquip.append(vlan) vlan_atual = net.vlan - vlan_aux = None - ambiente_aux = None for vlan in listaVlansDoEquip: if vlan.num_vlan == vlan_atual.num_vlan: @@ -178,19 +172,23 @@ def handle_post(self, request, user, *args, **kwargs): flag_vlan_error = False # Filter testing - if vlan.ambiente.filter is None or vlan_atual.ambiente.filter is None: + if vlan.ambiente.filter is None \ + or vlan_atual.ambiente.filter is None: flag_vlan_error = True else: # Test both environment's filters tp_equip_list_one = list() - for fet in FilterEquipType.objects.filter(filter=vlan_atual.ambiente.filter.id): + for fet in FilterEquipType.objects.filter( + filter=vlan_atual.ambiente.filter.id): tp_equip_list_one.append(fet.equiptype) tp_equip_list_two = list() - for fet in FilterEquipType.objects.filter(filter=vlan.ambiente.filter.id): + for fet in FilterEquipType.objects.filter( + filter=vlan.ambiente.filter.id): tp_equip_list_two.append(fet.equiptype) - if equip.tipo_equipamento not in tp_equip_list_one or equip.tipo_equipamento not in tp_equip_list_two: + if equip.tipo_equipamento not in tp_equip_list_one \ + or equip.tipo_equipamento not in tp_equip_list_two: flag_vlan_error = True # Filter case 3 - end # @@ -199,14 +197,23 @@ def handle_post(self, request, user, *args, **kwargs): ambiente_aux = vlan.ambiente vlan_aux = vlan nome_ambiente = '%s - %s - %s' % ( - vlan.ambiente.divisao_dc.nome, vlan.ambiente.ambiente_logico.nome, vlan.ambiente.grupo_l3.nome) - raise VlanNumberNotAvailableError(None, - """O ip informado não pode ser cadastrado, pois o equipamento %s, faz parte do ambiente %s (id %s), - que possui a Vlan de id %s, que também possui o número %s, e não é permitido que vlans que compartilhem o mesmo ambiente - por meio de equipamentos, possuam o mesmo número, edite o número de uma das Vlans ou adicione um filtro no ambiente para efetuar o cadastro desse IP no Equipamento Informado. - """ % (equip.nome, nome_ambiente, ambiente_aux.id, vlan_aux.id, vlan_atual.num_vlan)) - - # Persist + vlan.ambiente.divisao_dc.nome, + vlan.ambiente.ambiente_logico.nome, + vlan.ambiente.grupo_l3.nome) + raise VlanNumberNotAvailableError( + None, + """O ip informado não pode ser cadastrado, pois o + equipamento %s, faz parte do ambiente %s (id %s), + que possui a Vlan de id %s, que também possui + o número %s, e não é permitido que vlans que + compartilhem o mesmo ambiente por meio de + equipamentos, possuam o mesmo número, + edite o número de uma das Vlans ou adicione + um filtro no ambiente para efetuar o cadastro + desse IP no Equipamento Informado. """ % ( + equip.nome, nome_ambiente, ambiente_aux.id, + vlan_aux.id, vlan_atual.num_vlan)) + ip.save_ipv4(equip_id, user, net) list_ip = [] @@ -245,29 +252,29 @@ def handle_post(self, request, user, *args, **kwargs): return self.response(dumps_networkapi(network_map)) - except IpRangeAlreadyAssociation, e: - return self.response_error(347) - except VlanNumberNotAvailableError, e: + except IpRangeAlreadyAssociation as e: + return self.response_error(347, e.message) + except VlanNumberNotAvailableError as e: return self.response_error(314, e.message) - except InvalidValueError, e: + except InvalidValueError as e: return self.response_error(269, e.param, e.value) - except IpNotFoundError, e: + except IpNotFoundError as e: return self.response_error(150, e.message) except NetworkIPv4NotFoundError: return self.response_error(281) except EquipamentoNotFoundError: return self.response_error(117, ip_map.get('id_equipment')) - except IpNotAvailableError, e: + except IpNotAvailableError as e: return self.response_error(150, e.message) - except IpEquipmentNotFoundError, e: + except IpEquipmentNotFoundError as e: return self.response_error(150, e.message) - except IpEquipmentAlreadyAssociation, e: + except IpEquipmentAlreadyAssociation as e: return self.response_error(150, e.message) except UserNotAuthorizedError: return self.not_authorized() except XMLError, x: self.log.error(u'Error reading the XML request.') return self.response_error(3, x) - except (IpError, NetworkIPv4Error, EquipamentoError, GrupoError), e: + except (IpError, NetworkIPv4Error, EquipamentoError, GrupoError) as e: self.log.error(e) return self.response_error(1) From 1b1699e568b2f70644c61280d1d5fc9fe4ae629e Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Tue, 5 Jan 2021 10:28:09 -0300 Subject: [PATCH 2/6] allow to allocate the first and last ip --- networkapi/ip/models.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/networkapi/ip/models.py b/networkapi/ip/models.py index 6e7dbcb3e..b854cd458 100644 --- a/networkapi/ip/models.py +++ b/networkapi/ip/models.py @@ -1990,15 +1990,17 @@ def create_v3(self, ip_map, locks_used=[]): if ip4_object not in ipsv4: if ip4_object in net4: + # allow to allocate the first and last ip + flag = True - first_ip_network = int(net4.network) - bcast_ip_network = int(net4.broadcast) - - ipv4_network = int(ip4_object) - + # first_ip_network = int(net4.network) + # bcast_ip_network = int(net4.broadcast) + # + # ipv4_network = int(ip4_object) + # # First and last ip are reserved in network - if first_ip_network <= ipv4_network < bcast_ip_network: - flag = True + # if first_ip_network <= ipv4_network < bcast_ip_network: + # flag = True if flag is False: raise IpNotAvailableError( From b23f7106e60a4a06a23f2ceca5f3cf35d65272e9 Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Tue, 5 Jan 2021 17:20:58 -0300 Subject: [PATCH 3/6] refactor ip tests to allow create ip in 31 and 32 mask networks --- networkapi/api_ip/tests/sanity/ipv4/sync/test_post.py | 8 +++----- networkapi/api_ip/v4/tests/sanity/ipv4/sync/test_post.py | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/networkapi/api_ip/tests/sanity/ipv4/sync/test_post.py b/networkapi/api_ip/tests/sanity/ipv4/sync/test_post.py index 95ef0762b..5f2b8743d 100644 --- a/networkapi/api_ip/tests/sanity/ipv4/sync/test_post.py +++ b/networkapi/api_ip/tests/sanity/ipv4/sync/test_post.py @@ -102,7 +102,8 @@ def test_try_create_ip_associating_to_equipment(self): response.data['ips'][0]['ip_formated']) def test_try_create_ip_in_full_network(self): - """Tests if NAPI deny an IPv4 manually creation in a full network.""" + """ Tests if NAPI deny an IPv4 manually creation in a full network. + Refactor to allow create the ip.""" name_file = 'api_ip/tests/sanity/ipv4/json/post/ipv4_10_0_4_1_net_8.json' response = self.client.post( @@ -111,10 +112,7 @@ def test_try_create_ip_in_full_network(self): content_type='application/json', HTTP_AUTHORIZATION=self.get_http_authorization('test')) - self.compare_status(400, response.status_code) - self.compare_values( - 'Ip 10.0.4.1 not available for network 8.', - response.data['detail']) + self.compare_status(201, response.status_code) def test_try_create_out_of_range_ip_in_network(self): """Tests if NAPI deny out of range network IPv4 manually creation.""" diff --git a/networkapi/api_ip/v4/tests/sanity/ipv4/sync/test_post.py b/networkapi/api_ip/v4/tests/sanity/ipv4/sync/test_post.py index c9cf80baa..8367e1463 100644 --- a/networkapi/api_ip/v4/tests/sanity/ipv4/sync/test_post.py +++ b/networkapi/api_ip/v4/tests/sanity/ipv4/sync/test_post.py @@ -102,7 +102,8 @@ def test_try_create_ip_associating_to_equipment(self): response.data['ips'][0]['ip_formated']) def test_try_create_ip_in_full_network(self): - """V4 Tests if NAPI deny an IPv4 manually creation in a full network.""" + """ V4 Tests if NAPI deny an IPv4 manually creation in a full network. + Refactor to allow create the ip.""" name_file = 'api_ip/tests/sanity/ipv4/json/post/ipv4_10_0_4_1_net_8.json' response = self.client.post( @@ -111,10 +112,7 @@ def test_try_create_ip_in_full_network(self): content_type='application/json', HTTP_AUTHORIZATION=self.get_http_authorization('test')) - self.compare_status(400, response.status_code) - self.compare_values( - 'Ip 10.0.4.1 not available for network 8.', - response.data['detail']) + self.compare_status(201, response.status_code) def test_try_create_out_of_range_ip_in_network(self): """V4 Tests if NAPI deny out of range network IPv4 manually creation.""" From 5ae9c8ac9726c62d4792ea03b749e2be72bf5009 Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Wed, 6 Jan 2021 16:02:49 -0300 Subject: [PATCH 4/6] refator to get the interface description from database --- networkapi/api_interface/facade.py | 6 ++---- networkapi/interface/models.py | 13 +++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/networkapi/api_interface/facade.py b/networkapi/api_interface/facade.py index 2d2a2745c..ee149ab61 100644 --- a/networkapi/api_interface/facade.py +++ b/networkapi/api_interface/facade.py @@ -377,7 +377,7 @@ def generate_and_deploy_interface_config_sync(user, id_interface): file_to_deploy = _generate_config_file(interfaces) # TODO Deploy config file - lockvar = LOCK_INTERFACE_DEPLOY_CONFIG % (interface.equipamento.id) + lockvar = LOCK_INTERFACE_DEPLOY_CONFIG % interface.equipamento.id status_deploy = deploy_config_in_equipment_synchronous( file_to_deploy, interface.equipamento, lockvar) @@ -554,9 +554,7 @@ def _generate_dict(interface): key_dict['NATIVE_VLAN'] = interface.vlan_nativa key_dict['USE_MCLAG'] = 1 key_dict['INTERFACE_NAME'] = interface.interface - key_dict['INTERFACE_DESCRIPTION'] = str( - interface.ligacao_front.equipamento.nome - ) + ' ' + str(interface.ligacao_front.interface) + key_dict['INTERFACE_DESCRIPTION'] = interface.descricao key_dict['INTERFACE_TYPE'] = interface.tipo.tipo if key_dict['INTERFACE_TYPE'] in 'trunk': vlan_range_results = get_vlan_range(interface) diff --git a/networkapi/interface/models.py b/networkapi/interface/models.py index d822e23e8..4e5e1d784 100644 --- a/networkapi/interface/models.py +++ b/networkapi/interface/models.py @@ -856,14 +856,25 @@ def connecting_interfaces(self, interfaces): if link_a in "front": interface_a.ligacao_front = interface_b + interface_a.descricao = str(interface_a.ligacao_front.equipamento.nome + ) + ' ' + str(interface_a.ligacao_front.interface) + elif link_a in "back": interface_a.ligacao_back = interface_b + interface_a.descricao = str(interface_a.ligacao_back.equipamento.nome + ) + ' ' + str(interface_a.ligacao_back.interface) interface_a.save() if link_b in "front": interface_b.ligacao_front = interface_a + interface_b.descricao = str(interface_b.ligacao_front.equipamento.nome + ) + ' ' + str(interface_b.ligacao_front.interface) + elif link_b in "back": interface_b.ligacao_back = interface_a + interface_b.descricao = str(interface_b.ligacao_back.equipamento.nome + ) + ' ' + str(interface_b.ligacao_back.interface) + interface_b.save() def disconnecting_interfaces(self, interfaces): @@ -877,6 +888,7 @@ def disconnecting_interfaces(self, interfaces): if interface_a.ligacao_back: if interface_a.ligacao_back.id == interface_b.id: interface_a.ligacao_back = None + interface_a.descricao = None interface_a.save() if interface_b.ligacao_front: @@ -885,6 +897,7 @@ def disconnecting_interfaces(self, interfaces): if interface_b.ligacao_back: if interface_b.ligacao_back.id == interface_a.id: interface_b.ligacao_back = None + interface_b.descricao = None interface_b.save() def remove_connection(self, front=None, back=None): From f237581c8aa81083da1b3ac194f495f9ab65aecb Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Wed, 13 Jan 2021 16:06:49 -0300 Subject: [PATCH 5/6] get vrf name from equipment's access when use tftp command --- networkapi/plugins/Cisco/NXOS/BGP/Cli.py | 10 +++++++--- networkapi/plugins/factory.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/networkapi/plugins/Cisco/NXOS/BGP/Cli.py b/networkapi/plugins/Cisco/NXOS/BGP/Cli.py index eba21c7c2..bb1eb2296 100644 --- a/networkapi/plugins/Cisco/NXOS/BGP/Cli.py +++ b/networkapi/plugins/Cisco/NXOS/BGP/Cli.py @@ -60,7 +60,7 @@ class Generic(BasePlugin): WARNING_REGEX = 'config ignored|Warning' ERROR_REGEX = '[Ee][Rr][Rr][Oo][Rr]|[Ff]ail|\%|utility is occupied' - management_vrf = 'BEVrf' + management_vrf = 'management' admin_privileges = 15 VALID_TFTP_PUT_MESSAGE = 'bytes successfully copied' VALID_TFTP_PUT_MESSAGE_NXS6001 = 'Copy complete' @@ -421,12 +421,16 @@ def _copy_script_file_to_config(self, filename, By default, plugin should apply file in running configuration (active) """ + vrf = self.equipment.equipamentoacesso_set.all()[0].vrf.internal_name \ + if self.equipment.equipamentoacesso_set.all()[0].vrf \ + else self.management_vrf + command = 'copy tftp://{}/{} {} vrf {}\n\n'.format( - self.tftpserver, filename, destination, self.management_vrf) + self.tftpserver, filename, destination, vrf) file_copied = 0 retries = 0 - while(not file_copied and retries < self.MAX_TRIES): + while not file_copied and retries < self.MAX_TRIES: if retries is not 0: sleep(self.RETRY_WAIT_TIME) diff --git a/networkapi/plugins/factory.py b/networkapi/plugins/factory.py index 86790383d..b18ea0b62 100644 --- a/networkapi/plugins/factory.py +++ b/networkapi/plugins/factory.py @@ -92,7 +92,7 @@ def get_plugin(cls, **kwargs): return Cumulus if re.search('JUNIPER', marca.upper(), re.DOTALL): if re.search('QFX10008', modelo.upper(), re.DOTALL) \ - or re.search('QFX5120-48T', modelo.upper(), re.DOTALL): + or re.search('QFX5120-48T', modelo.upper(), re.DOTALL): from .Juniper.JUNOS.plugin import JUNOS return JUNOS raise NotImplementedError('plugin not implemented') From 8feea15f8188b00e2aa62acad4d881eb29399ad0 Mon Sep 17 00:00:00 2001 From: "laura.panzariello" Date: Mon, 18 Jan 2021 16:30:58 -0300 Subject: [PATCH 6/6] fix interface type --- networkapi/api_channel/facade.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networkapi/api_channel/facade.py b/networkapi/api_channel/facade.py index 5a822b6eb..14fbba264 100644 --- a/networkapi/api_channel/facade.py +++ b/networkapi/api_channel/facade.py @@ -74,7 +74,7 @@ def create(self, data): for interface in interfaces: iface = Interface.objects.get(id=interface) - type_obj = TipoInterface.objects.get(tipo=int_type) + type_obj = TipoInterface.objects.get(tipo=int_type.lower()) if iface.channel: raise InterfaceError(