Source code for networkapi.vlan.models

# -*- coding: utf-8 -*-
from __future__ import with_statement

import logging

from _mysql_exceptions import OperationalError
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models import get_model
from django.db.models import Q

from networkapi.admin_permission import AdminPermission
from networkapi.distributedlock import LOCK_ENVIRONMENT_ALLOCATES
from networkapi.distributedlock import LOCK_VLAN
from networkapi.filter.models import verify_subnet_and_equip
from networkapi.infrastructure.ipaddr import IPNetwork
from networkapi.models.BaseModel import BaseModel
from networkapi.queue_tools import queue_keys
from networkapi.queue_tools.rabbitmq import QueueManager
from networkapi.semaforo.model import Semaforo
from networkapi.settings import MAX_VLAN_NUMBER_01
from networkapi.settings import MAX_VLAN_NUMBER_02
from networkapi.settings import MIN_VLAN_NUMBER_01
from networkapi.settings import MIN_VLAN_NUMBER_02
from networkapi.util import clone
from networkapi.util import network
from networkapi.util.decorators import cached_property
from networkapi.util.geral import create_lock_with_blocking
from networkapi.util.geral import destroy_lock
from networkapi.util.geral import get_app


[docs]class VlanError(Exception): """Representa um erro ocorrido durante acesso à tabelas relacionadas com Vlan.""" def __init__(self, cause, message=None): self.cause = cause self.message = message def __str__(self): msg = u'Causa: %s, Mensagem: %s' % (self.cause, self.message) return msg.encode('utf-8', 'replace')
[docs]class VlanErrorV3(Exception): def __init__(self, message): self.message = message def __str__(self): return str(self.message)
[docs]class NetworkTypeNotFoundError(VlanError): """Returns exception when trying to get network type by its identifier.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class NetTypeUsedByNetworkError(VlanError): """Return exception when trying to remove network type used by network.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class NetworkTypeNameDuplicatedError(VlanError): """Returns exception when trying to insert/update network type with same name as other.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNotFoundError(VlanError): """Retorna exceção para pesquisa de vlan por nome ou por chave primária.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNumberNotAvailableError(VlanError): """Retorna exceção porque não existe um número de VLAN disponível para criar uma nova VLAN.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNumberEnvironmentNotAvailableError(VlanError): def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNetworkAddressNotAvailableError(VlanError): """Retorna exceção porque não existe um endereço de rede disponível para criar uma nova VLAN.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNameDuplicatedError(VlanError): """Retorna exceção porque já existe uma VLAN cadastrada com o mesmo nome.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanACLDuplicatedError(VlanError): """Retorna exceção porque já existe uma VLAN cadastrada com o mesmo nome de arquivo ACL.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanInactiveError(VlanError): """Retorna exceção porque está inativa.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanNetworkError(VlanError): """Retorna exceção caso não consiga remover uma rede""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class AclNotFoundError(VlanError): """Retorna exceção para acl inexistente.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class VlanCantDeallocate(VlanError): """Retorna exceção porque Vlan está ativa e não pode ser excluída.""" def __init__(self, cause, message=None): VlanError.__init__(self, cause, message)
[docs]class TipoRedeNotFoundError(VlanError): pass
[docs]class TipoRedeUsedByVlanError(VlanError): pass
[docs]class TipoRedeNameDuplicatedError(VlanError): pass
[docs]class TipoRede(BaseModel): id = models.AutoField(primary_key=True, db_column='id_tipo_rede') tipo_rede = models.CharField(max_length=100) log = logging.getLogger('TipoRede') class Meta(BaseModel.Meta): db_table = u'tipo_rede' managed = True
[docs] @classmethod def get_by_pk(cls, id): try: return TipoRede.objects.filter(id=id).uniqueResult() except ObjectDoesNotExist, e: raise NetworkTypeNotFoundError( e, u'There is no network type with pk = %s.' % id) except OperationalError, e: cls.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: cls.log.error(u'Failed to get network type.') raise VlanError(e, u'Failed to get network type.')
[docs] @classmethod def get_by_name(cls, name): try: tipos = TipoRede.objects.filter(tipo_rede__iexact=name) if len(tipos) == 0: raise NetworkTypeNotFoundError( None, u'There is no network type with name = %s.' % name) return tipos[0] except NetworkTypeNotFoundError, e: raise e except Exception, e: cls.log.error(u'Failed to get network type.') raise VlanError(e, u'Failed to get network type.')
[docs]class Vlan(BaseModel): log = logging.getLogger('Vlan') id = models.AutoField(primary_key=True, db_column='id_vlan') nome = models.CharField(max_length=50) num_vlan = models.IntegerField() ambiente = models.ForeignKey('ambiente.Ambiente', db_column='id_ambiente') descricao = models.CharField(max_length=200, blank=True) acl_file_name = models.CharField(max_length=200, blank=True) acl_valida = models.BooleanField() acl_file_name_v6 = models.CharField(max_length=200, blank=True) acl_valida_v6 = models.BooleanField() ativada = models.BooleanField() vrf = models.CharField(max_length=100, null=True, db_column='vrf') acl_draft = models.TextField(blank=True, null=True, db_column='acl_draft') acl_draft_v6 = models.TextField( blank=True, null=True, db_column='acl_draft_v6') def _get_networks_ipv4(self): """Returns networks v4.""" networkipv4 = self.networkipv4_set.all() return networkipv4 networks_ipv4 = property(_get_networks_ipv4) def _get_networks_ipv6(self): """Returns networks v6.""" networkipv6 = self.networkipv6_set.all() return networkipv6 networks_ipv6 = property(_get_networks_ipv6) class Meta(BaseModel.Meta): db_table = u'vlans' managed = True unique_together = ( ('nome', 'ambiente'), ('num_vlan', 'ambiente') ) @cached_property def vrfs(self): return self.get_vrf().prefetch_related() @cached_property def groups_permissions(self): ogp_models = get_app('api_ogp', 'models') perms = ogp_models.ObjectGroupPermission\ .get_by_object(self.id, AdminPermission.OBJ_TYPE_VLAN) return perms
[docs] def get_by_pk(self, vlan_id): """Get Vlan by id. @return: Vlan. @raise VlanNotFoundError: Vlan is not registered. @raise VlanError: Failed to search for the Vlan. @raise OperationalError: Lock wait timeout exceed """ try: return Vlan.objects.get(id=vlan_id) except ObjectDoesNotExist, e: raise VlanNotFoundError( e, u'Dont there is a Vlan by pk = %s.' % vlan_id) except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def get_vlan_by_acl(self, acl_file): try: vlan = Vlan.objects.filter(acl_file_name=acl_file).uniqueResult() if self.id is not None: if vlan.id == self.id: return raise VlanACLDuplicatedError( None, 'uThere is already an Vlan with the Acl - Ipv4 = %s.' % acl_file) except VlanACLDuplicatedError, e: raise VlanACLDuplicatedError(e, e.message) except ObjectDoesNotExist, e: pass except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def get_vlan_by_acl_v6(self, acl_file_v6): try: vlan = Vlan.objects.filter( acl_file_name_v6=acl_file_v6).uniqueResult() if self.id is not None: if vlan.id == self.id: return raise VlanACLDuplicatedError( None, 'uThere is already an Vlan with the Acl - Ipv6 = %s.' % acl_file_v6) except VlanACLDuplicatedError, e: raise VlanACLDuplicatedError(e, e.message) except ObjectDoesNotExist, e: pass except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def exist_vlan_name_in_environment(self, id_vlan=None): try: vlans = Vlan.objects.filter( nome__iexact=self.nome, ambiente__id=self.ambiente.id ) if id_vlan: vlans = vlans.exclude(id=id_vlan) if vlans: return True else: return False except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def exist_vlan_num_in_environment(self, id_vlan=None): try: vlans = Vlan.objects.filter( num_vlan=self.num_vlan, ambiente__id=self.ambiente.id ) if id_vlan: vlans = vlans.exclude(id=id_vlan) if vlans: return True else: return False except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def search_vlan_numbers(self, environment_id, min_num, max_num): try: return Vlan.objects.filter( num_vlan__range=(min_num, max_num), ambiente__id=environment_id ).values_list( 'num_vlan', flat=True ).distinct().order_by('num_vlan') except Exception, e: self.log.error(u'Failure to search the Vlans.') raise VlanError(e, u'Failure to search the Vlans.')
[docs] def search(self, environment_id=None): try: v = Vlan.objects.all() if environment_id is not None: v = v.filter(ambiente__id=environment_id) return v except Exception, e: self.log.error(u'Failure to search the Vlans.') raise VlanError(e, u'Failure to search the Vlans.')
[docs] def calculate_vlan_number(self, min_num, max_num, list_available=False): from networkapi.equipamento.models import EquipamentoAmbiente """ Caculate if has a number available in range (min_num/max_num) to specified environment @param min_num: Minimum number that the vlan can be created. @param max_num: Maximum number that the vlan can be created. @param list_available: If = True, return the list of numbers availables @return: None when hasn't a number available | num_vlan when found a number available """ interval = range(min_num, max_num + 1) # Vlan numbers in interval in the same environment vlan_numbers_in_interval = self.search_vlan_numbers( self.ambiente_id, min_num, max_num) # Find equipment's ids from environmnet that is 'switches', # 'roteadores' or 'balanceadores' id_equipamentos = EquipamentoAmbiente.objects.filter( equipamento__tipo_equipamento__id__in=[1, 3, 5], ambiente__id=self.ambiente_id ).values_list('equipamento', flat=True) # Vlan numbers in others environment but in environment that has # equipments found in before filter ('switches', 'roteadores' or # 'balanceadores') vlans_others_environments = Vlan.objects.exclude( ambiente__id=self.ambiente_id ).filter( ambiente__equipamentoambiente__equipamento__id__in=id_equipamentos ).values_list('num_vlan', flat=True) # Clean duplicates numbers and update merge 'vlan_numbers_in_interval' # with 'vlans_others_environments' vlan_numbers_in_interval = set(vlan_numbers_in_interval) vlan_numbers_in_interval.update(vlans_others_environments) self.log.debug('Interval: %s.', interval) self.log.debug('VLANs in interval: %s.', vlan_numbers_in_interval) # if len(interval) > len(vlan_numbers_in_interval): diff_set = set(interval) - set(vlan_numbers_in_interval) self.log.debug('Difference in the lists: %s.', diff_set) if list_available: return diff_set for num_vlan in diff_set: return num_vlan return None
[docs] def activate(self, authenticated_user): """ Set column ativada = 1""" try: self.ativada = 1 self.save() vlan_slz = get_app('api_vlan', 'serializers') serializer = vlan_slz.VlanV3Serializer( self, include=('environment__basic',), exclude=( 'acl_draft', 'acl_draft_v6', 'acl_valida_v6', 'acl_file_name_v6', 'acl_valida', 'acl_file_name', ) ) data_to_queue = serializer.data data_to_queue.update({ 'description': queue_keys.VLAN_ACTIVATE }) # Send to Queue queue_manager = QueueManager(broker_vhost='tasks', queue_name='tasks.aclapi', exchange_name='tasks.aclapi', routing_key='tasks.aclapi') queue_manager.append({ 'action': queue_keys.VLAN_ACTIVATE, 'kind': queue_keys.VLAN_KEY, 'data': data_to_queue }) queue_manager.send() except Exception, e: self.log.error(u'Falha ao salvar a VLAN.') raise VlanError(e, u'Falha ao salvar a VLAN.')
[docs] def remove(self, authenticated_user): """ Update status column to 'active = 0' @param authenticate_user: User authenticate @raise VlanError: Exception """ try: self.ativada = 0 self.save() vlan_slz = get_app('api_vlan', 'serializers') serializer = vlan_slz.VlanV3Serializer( self, include=('environment__basic',), exclude=( 'acl_draft', 'acl_draft_v6', 'acl_valida_v6', 'acl_file_name_v6', 'acl_valida', 'acl_file_name', ) ) data_to_queue = serializer.data data_to_queue.update({ 'description': queue_keys.VLAN_DEACTIVATE }) # Send to Queue queue_manager = QueueManager(broker_vhost='tasks', queue_name='tasks.aclapi', exchange_name='tasks.aclapi', routing_key='tasks.aclapi') queue_manager.append({ 'action': queue_keys.VLAN_DEACTIVATE, 'kind': queue_keys.VLAN_KEY, 'data': data_to_queue }) queue_manager.send() except Exception, e: self.log.error(u'Falha ao salvar a VLAN.') raise VlanError(e, u'Falha ao salvar a VLAN.')
[docs] def create_new(self, authenticated_user, min_num_01, max_num_01, min_num_02, max_num_02): """ Create a Vlan with the new Model The fields num_vlan, acl_file_name, acl_valida and ativada will be generated automatically @return: nothing """ if self.nome is not None: self.nome = self.nome.upper() # Name VLAN can not be duplicated in the environment if self.exist_vlan_name_in_environment(): raise VlanNameDuplicatedError( None, 'Name VLAN can not be duplicated in the environment.') # Calculate Number VLAN self.num_vlan = self.calculate_vlan_number(min_num_01, max_num_01) if self.num_vlan is None: self.num_vlan = self.calculate_vlan_number(min_num_02, max_num_02) if self.num_vlan is None: raise VlanNumberNotAvailableError( None, u'Number VLAN unavailable for environment %d.' % self.ambiente.id) # Default values self.acl_file_name = self.nome self.acl_valida = 0 self.ativada = 0 try: self.save() except Exception, e: msg = u'Error persisting a VLAN.' self.log.error(msg) raise VlanError(e, msg)
[docs] def create(self, authenticated_user, min_num_01, max_num_01, min_num_02, max_num_02): """Insere uma nova VLAN. O valor dos campos num_vlan, rede_oct1, rede_oct2, rede_oct3, rede_oct4, bloco, broadcast, masc_oct1, masc_oct2, masc_oct3, masc_oct4, acl_file_name, acl_valida e ativada é gerado internamente. Os demais campos devem ser fornecidos. @param min_num_01: Valor inicial do intervalo 01 para calcular o número da VLAN. @param max_num_01: Valor final do intervalo 01 para calcular o número da VLAN. @param min_num_02: Valor inicial do intervalo 02 para calcular o número da VLAN. @param max_num_02: Valor final do intervalo 02 para calcular o número da VLAN. @return: nothing @raise NetworkTypeNotFoundError: Tipo de Rede não cadastrada no banco de dados. @raise AmbienteNotFoundError: Ambiente não cadastrado no banco de dados. @raise AmbienteError: Falha ao pesquisar o ambiente. @raise VlanNameDuplicatedError: Nome da VLAN duplicado. @raise VlanNumberNotAvailableError: Não encontra um número de VLAN disponível em um dos intervalos (2 até 1001) ou (1006 até 4094) para o ambiente informado. @raise VlanNetworkAddressNotAvailableError: Não existe um endereço de rede disponível para VLAN que não seja sub-rede ou super-rede de um endereço existe no cadastro de VLANs. @raise VlanError: Erro não esperado ao executar o save. """ if self.nome is not None: self.nome = self.nome.upper() # Tipo de Rede if self.tipo_rede.id is not None: self.tipo_rede = TipoRede().get_by_pk(self.tipo_rede.id) # Verificar duplicidade do Nome da VLAN if self.exist_vlan_name_in_environment(): raise VlanNameDuplicatedError( None, 'VLAN com nome duplicado dentro do ambiente.') Semaforo.lock(Semaforo.ALOCAR_VLAN_ID) # Calcular o Numero da VLAN self.num_vlan = self.calculate_vlan_number(min_num_01, max_num_01) if self.num_vlan is None: self.num_vlan = self.calculate_vlan_number(min_num_02, max_num_02) if self.num_vlan is None: raise VlanNumberNotAvailableError( None, u'Não existe número de VLAN disponível para o ambiente %d.' % self.ambiente.id) # Calcular o Endereço de Rede da VLAN vlan_address = self.calculate_vlan_address() if (len(vlan_address) == 0): raise VlanNetworkAddressNotAvailableError( None, u'Não existe endereço de rede disponível para o cadastro da VLAN.') self.rede_oct1, self.rede_oct2, self.rede_oct3, self.rede_oct4 = vlan_address # Valores Default self.bloco = 24 self.masc_oct1 = 255 self.masc_oct2 = 255 self.masc_oct3 = 255 self.masc_oct4 = 0 self.broadcast = '%d.%d.%d.255' % ( self.rede_oct1, self.rede_oct2, self.rede_oct3) self.acl_file_name = self.nome self.acl_valida = 0 self.ativada = 0 try: self.save() except Exception, e: self.log.error(u'Falha ao inserir a VLAN.') raise VlanError(e, u'Falha ao inserir a VLAN.')
[docs] def get_by_number_and_environment(self, number, environment): """Get Vlan by number. @return: Vlan. @raise VlanNotFoundError: Vlan is not registered. @raise VlanError: Failed to search for the Vlan. @raise OperationalError: Lock wait timeout exceed """ try: return Vlan.objects.filter( num_vlan=number, ambiente=environment).uniqueResult() except ObjectDoesNotExist, e: raise VlanNotFoundError( e, u'Dont there is a Vlan by number = %s.' % number) except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def get_by_number(self, number): """Get Vlan by number. @return: Vlan. @raise VlanNotFoundError: Vlan is not registered. @raise VlanError: Failed to search for the Vlan. @raise OperationalError: Lock wait timeout exceed """ try: return Vlan.objects.filter(num_vlan=number).uniqueResult() except ObjectDoesNotExist, e: raise VlanNotFoundError( e, u'Dont there is a Vlan by number = %s.' % number) except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def get_by_name(self, name): """Get Vlan by name. @return: Vlan. @raise VlanNotFoundError: Vlan is not registered. @raise VlanError: Failed to search for the Vlan. @raise OperationalError: Lock wait timeout exceed """ try: return Vlan.objects.filter(nome=name).uniqueResult() except ObjectDoesNotExist, e: raise VlanNotFoundError( e, u'Dont there is a Vlan by name = %s.' % name) except OperationalError, e: self.log.error(u'Lock wait timeout exceeded.') raise OperationalError( e, u'Lock wait timeout exceeded; try restarting transaction') except Exception, e: self.log.error(u'Failure to search the Vlan.') raise VlanError(e, u'Failure to search the Vlan.')
[docs] def insert_vlan(self, authenticated_user): """ Insere uma nova Vlan. @return ID new Vlan. @raise VlanNameDuplicatedError: Nome do Vlan já existe. @raise VlanNumberEnvironmentNotAvailableError: Numero e Ambiente da VLan já existe. @raise VlanError: Erro ao cadastrar Vlan. """ from networkapi.equipamento.models import TipoEquipamento try: self.get_by_number_and_environment(self.num_vlan, self.ambiente) ambiente = '%s - %s - %s' % (self.ambiente.divisao_dc.nome, self.ambiente.ambiente_logico.nome, self.ambiente.grupo_l3.nome) raise VlanNumberEnvironmentNotAvailableError( None, 'Já existe uma VLAN cadastrada com o número %s no ambiente %s' % (self.num_vlan, ambiente)) except VlanNotFoundError: pass ambiente = self.ambiente filter = ambiente.filter equipment_types = TipoEquipamento.objects.filter( filterequiptype__filter=filter) equips = list() envs = list() envs_aux = list() # Get all equipments from the environment being tested # that are not supposed to be filtered # (not the same type of the equipment type of a filter of the environment) for env in ambiente.equipamentoambiente_set.all().exclude( equipamento__tipo_equipamento__in=equipment_types): equips.append(env.equipamento) # Get all environment that the equipments above are included for equip in equips: for env in equip.equipamentoambiente_set.all(): if env.ambiente_id not in envs_aux: envs.append(env.ambiente) envs_aux.append(env.ambiente_id) # Check in all vlans from all environments above # if there is a vlan with the same vlan number of the # vlan being tested for env in envs: for vlan in env.vlan_set.all(): if int(vlan.num_vlan) == int(self.num_vlan): raise VlanNumberEnvironmentNotAvailableError( None, 'Já existe uma VLAN cadastrada com o número %s com um equipamento compartilhado nesse ambiente' % (self.num_vlan)) # Name VLAN can not be duplicated in the environment if self.exist_vlan_name_in_environment(): raise VlanNameDuplicatedError( None, 'Name VLAN can not be duplicated in the environment.') try: return self.save() except Exception, e: self.log.error(u'Falha ao inserir VLAN.') raise VlanError(e, u'Falha ao inserir VLAN.')
[docs] def edit_vlan(self, authenticated_user, change_name, change_number_environment): """ Edita uma Vlan. @return None. @raise VlanNameDuplicatedError: Nome do Vlan já existe. @raise VlanNumberEnvironmentNotAvailableError: Numero e Ambiente da VLan já existe. @raise VlanError: Erro ao cadastrar Vlan. """ if change_number_environment: try: self.get_by_number_and_environment( self.num_vlan, self.ambiente) ambiente = '%s - %s - %s' % (self.ambiente.divisao_dc.nome, self.ambiente.ambiente_logico.nome, self.ambiente.grupo_l3.nome) raise VlanNumberEnvironmentNotAvailableError( None, 'Já existe uma VLAN cadastrada com o número %s no ambiente %s' % (self.num_vlan, ambiente)) except VlanNotFoundError: pass if change_number_environment: ambiente = self.ambiente equips = list() envs = list() for env in ambiente.equipamentoambiente_set.all(): equips.append(env.equipamento) for equip in equips: for env in equip.equipamentoambiente_set.all(): if env not in envs: envs.append(env.ambiente) for env in envs: for vlan in env.vlan_set.all(): if int(vlan.num_vlan) == int(self.num_vlan) and int(vlan.id) != int(self.id): if self.ambiente.filter_id is None or vlan.ambiente.filter_id is None or int(vlan.ambiente.filter_id) != int(self.ambiente.filter_id): raise VlanNumberEnvironmentNotAvailableError( None, 'Já existe uma VLAN cadastrada com o número %s com um equipamento compartilhado nesse ambiente' % (self.num_vlan)) old_vlan = self.get_by_pk(self.id) old_env = old_vlan.ambiente # Old env if old_env.filter is not None: if self.check_env_shared_equipment(old_env): if self.ambiente.filter_id != old_env.filter_id: raise VlanNumberEnvironmentNotAvailableError( None, 'Um dos equipamentos associados com o ambiente desta Vlan também está associado com outro ambiente que tem uma rede com a mesma faixa, adicione filtros nos ambientes se necessário.') if change_name: # Name VLAN can not be duplicated in the environment if self.exist_vlan_name_in_environment(): raise VlanNameDuplicatedError( None, 'Name VLAN can not be duplicated in the environment.') try: return self.save() except Exception, e: self.log.error(u'Falha ao inserir VLAN.') raise VlanError(e, u'Falha ao inserir VLAN.')
[docs] def check_env_shared_equipment(self, old_env): # Check if the environment is sharing an equipment by the network # Envs using old filter envs_old_filter = old_env.filter.ambiente_set.all() # Vlans in listed envs vlans = list() for env_old_filter in envs_old_filter: for vlan in env_old_filter.vlan_set.all(): vlans.append(vlan) # Nets in vlan nets_ipv4 = list() nets_ipv6 = list() for vlan in vlans: for net in vlan.networkipv4_set.all(): nets_ipv4.append({'net': net, 'vlan_env': vlan.ambiente}) for net in vlan.networkipv6_set.all(): nets_ipv6.append({'net': net, 'vlan_env': vlan.ambiente}) # Verify subnet ipv4 for i in range(0, len(nets_ipv4)): net = nets_ipv4[i].get('net') ip = '%s.%s.%s.%s/%s' % (net.oct1, net.oct2, net.oct3, net.oct4, net.block) network_ip_verify = IPNetwork(ip) nets_ipv4_aux = clone(nets_ipv4) nets_ipv4_aux.remove(nets_ipv4[i]) if verify_subnet_and_equip(nets_ipv4_aux, network_ip_verify, 'v4', net, nets_ipv4[i].get('vlan_env')): env_aux_id = nets_ipv4[i].get('vlan_env').id if old_env.id == env_aux_id: return True # Verify subnet ipv6 for i in range(0, len(nets_ipv6)): net = nets_ipv6[i].get('net') ip = '%s:%s:%s:%s:%s:%s:%s:%s/%d' % (net.block1, net.block2, net.block3, net.block4, net.block5, net.block6, net.block7, net.block8, net.block) network_ip_verify = IPNetwork(ip) nets_ipv6_aux = clone(nets_ipv6) nets_ipv6_aux.remove(nets_ipv6[i]) if verify_subnet_and_equip(nets_ipv6_aux, network_ip_verify, 'v6', net, nets_ipv6[i].get('vlan_env')): env_aux_id = nets_ipv6[i].get('vlan_env').id if old_env.id == env_aux_id: return True return False
[docs] def delete(self): from networkapi.ip.models import IpCantBeRemovedFromVip try: if not self.ativada: for net4 in self.networkipv4_set.all(): net4.delete() for net6 in self.networkipv6_set.all(): net6.delete() else: raise VlanCantDeallocate( str(self.nome), 'Cant deallocate all relationships between vlan because its active.') super(Vlan, self).delete() except IpCantBeRemovedFromVip, e: cause = e.cause cause['Vlan'] = self.nome raise IpCantBeRemovedFromVip( cause, 'Esta Vlan possui uma Rede com Requisição Vip apontando para ela, e não pode ser excluída') except VlanCantDeallocate, e: raise e
[docs] def get_eqpt(self): """Returns list of equipments associated with environment.""" # Get all eqpts of environment eqpts = self.ambiente.eqpts # Filter of environment filenv = self.ambiente.filter # Use filter if filenv: eqpts = eqpts.exclude(equipamento__in=eqpts.filter( equipamento__tipo_equipamento__filterequiptype__filter=filenv) ) self.log.debug('Equipments of environment(filtered): %s' % eqpts) return eqpts
[docs] def get_vrf(self): # get vrf to filter vrf = get_model('api_vrf', 'Vrf') vrfs = vrf.objects.filter( Q( Q(vrfvlanequipment__equipment__in=self.get_eqpt()) & Q(vrfvlanequipment__vlan__id=self.id) ) | Q(id=self.ambiente.default_vrf_id) ) return vrfs
[docs] def validate_v3(self): """Make validations in values inputted.""" if self.exist_vlan_num_in_environment(self.id): msg = 'Number VLAN can not be duplicated in the environment.' self.log.error(msg) raise VlanErrorV3(msg) if self.exist_vlan_name_in_environment(self.id): msg = 'Name VLAN can not be duplicated in the environment.' self.log.error(msg) raise VlanErrorV3(msg) # Validate Number of vlan in environment related equips = self.get_eqpt() network.validate_vlan_conflict(equips, self.num_vlan, self.id)
[docs] def create_v3(self, vlan, user): """Create new vlan.""" try: env_model = get_model('ambiente', 'Ambiente') ogp_models = get_app('api_ogp', 'models') self.ambiente = env_model.get_by_pk(vlan.get('environment')) self.nome = vlan.get('name').upper() self.num_vlan = vlan.get('num_vlan') self.descricao = vlan.get('description') self.acl_file_name = vlan.get('acl_file_name') self.acl_valida = vlan.get('acl_valida', False) self.acl_file_name_v6 = vlan.get('acl_file_name_v6') self.acl_valida_v6 = vlan.get('acl_valida_v6', False) self.ativada = vlan.get('active', False) self.vrf = vlan.get('vrf') self.acl_draft = vlan.get('acl_draft') self.acl_draft_v6 = vlan.get('acl_draft_v6') # Get environments related envs = self.get_environment_related(use_vrf=False)\ .values_list('id', flat=True) except Exception, e: raise VlanErrorV3(e) else: # Create locks for environment locks_name = [LOCK_ENVIRONMENT_ALLOCATES % env for env in envs] locks_list = create_lock_with_blocking(locks_name) try: # Allocates 1 number of vlan automatically if not self.num_vlan: self.allocate_vlan() self.validate_v3() self.save() # Permissions perm = ogp_models.ObjectGroupPermission() perm.create_perms( vlan, self.id, AdminPermission.OBJ_TYPE_VLAN, user) # Allocates networkv4 netv4 = vlan.get('create_networkv4') if netv4: network_type = vlan.get('create_networkv4').get( 'network_type', None) prefix = vlan.get('create_networkv4').get('prefix', None) environmentvip = vlan.get('create_networkv4').get( 'environmentvip', None) dict_net = { 'network_type': network_type, 'prefix': prefix, 'vlan': self.id, 'environmentvip': environmentvip, } net4_model = get_model('ip', 'NetworkIPv4') netv4_obj = net4_model() netv4_obj.create_v3(dict_net, locks_used=locks_name) # Allocates networkv6 if vlan.get('create_networkv6'): network_type = vlan.get('create_networkv6').get( 'network_type', None) prefix = vlan.get('create_networkv6').get('prefix', None) environmentvip = vlan.get('create_networkv6').get( 'environmentvip', None) dict_net = { 'network_type': network_type, 'prefix': prefix, 'vlan': self.id, 'environmentvip': environmentvip, } net6_model = get_model('ip', 'NetworkIPv6') netv6_obj = net6_model() netv6_obj.create_v3(dict_net, locks_used=locks_name) except Exception, e: raise VlanErrorV3(e) finally: # Destroy locks destroy_lock(locks_list)
[docs] def update_v3(self, vlan, user): """Update vlan.""" try: env_model = get_model('ambiente', 'Ambiente') ogp_models = get_app('api_ogp', 'models') env = env_model.get_by_pk(vlan.get('environment')) self.ambiente = env self.nome = vlan.get('name') self.num_vlan = vlan.get('num_vlan') self.descricao = vlan.get('description') self.acl_file_name = vlan.get('acl_file_name') self.acl_valida = vlan.get('acl_valida', False) self.acl_file_name_v6 = vlan.get('acl_file_name_v6') self.acl_valida_v6 = vlan.get('acl_valida_v6', False) self.ativada = vlan.get('active', False) self.vrf = vlan.get('vrf') self.acl_draft = vlan.get('acl_draft') self.acl_draft_v6 = vlan.get('acl_draft_v6') old_vlan = self.get_by_pk(self.id) except Exception, e: raise VlanErrorV3(e) else: # Prepare locks for vlan locks_name = [LOCK_VLAN % self.id] # If the environment was changed, create lock to validate if old_vlan.ambiente != self.ambiente: # Get environments related envs = self.get_environment_related(use_vrf=False)\ .values_list('id', flat=True) # Prepare locks for environment locks_name += [LOCK_ENVIRONMENT_ALLOCATES % env_id for env_id in envs] # Create locks for environment and vlan locks_list = create_lock_with_blocking(locks_name) try: # Activate vlan can not be changed of environment if old_vlan.ativada: if old_vlan.ambiente != self.ambiente: msg = 'Environment can not be changed in vlan actived.' self.log.error(msg) raise VlanErrorV3(msg) if old_vlan.num_vlan != self.num_vlan: msg = 'Number Vlan can not be changed in vlan actived.' self.log.error(msg) raise VlanErrorV3(msg) if old_vlan.nome != self.nome: msg = 'Name Vlan can not be changed in vlan actived.' self.log.error(msg) raise VlanErrorV3(msg) # If the environment was changed, create lock to validate if old_vlan.ambiente != self.ambiente: # If vlan has networks of environment, can not be changed # of environment netv4_vip = self.networkipv4_set.filter( ambient_vip__isnull=False) netv6_vip = self.networkipv6_set.filter( ambient_vip__isnull=False) if netv4_vip or netv6_vip: msg = u'Not change vlan when networks are of' \ ' environment Vip.' self.log.error(msg) raise VlanErrorV3(msg) if self.networkipv4_set.all() or self.networkipv6_set.all(): # Validate conflicts of network(equal, subnet ou supernet) self.validate_network() # Validate name and number self.validate_v3() self.save() # Permissions perm = ogp_models.ObjectGroupPermission() perm.update_perms( vlan, self.id, AdminPermission.OBJ_TYPE_VLAN, user) except Exception, e: raise VlanErrorV3(e) finally: # Destroy locks destroy_lock(locks_list) return self
[docs] def delete_v3(self): ogp_models = get_app('api_ogp', 'models') ipcantberemovedfromvip = get_model('ip', 'IpCantBeRemovedFromVip') id_vlan = self.id try: if not self.ativada: for net4 in self.networkipv4_set.all(): net4.delete_v3() for net6 in self.networkipv6_set.all(): net6.delete_v3() else: self.log.error( 'Cant deallocate all relationships between vlan because ' 'its active.') raise VlanCantDeallocate( str(self.nome), 'Cant deallocate all relationships between vlan because ' 'its active.') super(Vlan, self).delete() except ipcantberemovedfromvip, e: cause = e.cause cause['Vlan'] = self.nome self.log.error( 'This Vlan has a Network with Vip Request pointing to it, and ' 'can not be deleted') raise ipcantberemovedfromvip( cause, 'This Vlan has a Network with Vip Request pointing to it, and ' 'can not be deleted') except VlanCantDeallocate, e: raise e # Deletes Permissions ogp_models.ObjectGroupPermission.objects.filter( object_type__name=AdminPermission.OBJ_TYPE_VLAN, object_value=id_vlan ).delete()
[docs] def activate_v3(self, locks_used): """Set column ativada = 1""" """ Send activate notication of network for queue of ACL configuration system. Update status column to 'ativada = 1'. @raise VlanErrorV3: Error activating a Vlan. """ locks_list = list() # Prepare locks for vlan lock_name = [LOCK_VLAN % self.id] if lock_name not in locks_used: # Create locks for environment and vlan locks_list = create_lock_with_blocking([lock_name]) try: vlan_slz = get_app('api_vlan', 'serializers') self.ativada = 1 serializer = vlan_slz.VlanV3Serializer( self, include=('environment__basic',), exclude=( 'acl_draft', 'acl_draft_v6', 'acl_valida_v6', 'acl_file_name_v6', 'acl_valida', 'acl_file_name', ) ) data_to_queue = serializer.data data_to_queue.update({ 'description': queue_keys.VLAN_ACTIVATE }) # Send to Queue queue_manager = QueueManager(broker_vhost='tasks', queue_name='tasks.aclapi', exchange_name='tasks.aclapi', routing_key='tasks.aclapi') queue_manager.append({ 'action': queue_keys.VLAN_ACTIVATE, 'kind': queue_keys.VLAN_KEY, 'data': data_to_queue }) queue_manager.send() self.save() except Exception, e: self.log.error(u'Error activating Vlan.: %s' % e) raise VlanErrorV3(u'Error activating Vlan.') finally: if locks_list: # Destroy locks destroy_lock(locks_list)
[docs] def deactivate_v3(self, locks_used): """ Send activate notication of vlan for queue of ACL configuration system. Update status column to 'ativada = 0'. @raise VlanErrorV3: Error disabling a Vlan. """ locks_list = list() # Prepare locks for vlan lock_name = [LOCK_VLAN % self.id] if lock_name not in locks_used: # Create locks for environment and vlan locks_list = create_lock_with_blocking([lock_name]) try: vlan_slz = get_app('api_vlan', 'serializers') self.ativada = 0 serializer = vlan_slz.VlanV3Serializer( self, include=('environment__basic',), exclude=( 'acl_draft', 'acl_draft_v6', 'acl_valida_v6', 'acl_file_name_v6', 'acl_valida', 'acl_file_name', ) ) data_to_queue = serializer.data data_to_queue.update({ 'description': queue_keys.VLAN_DEACTIVATE }) # Send to Queue queue_manager = QueueManager(broker_vhost='tasks', queue_name='tasks.aclapi', exchange_name='tasks.aclapi', routing_key='tasks.aclapi') queue_manager.append({ 'action': queue_keys.VLAN_DEACTIVATE, 'kind': queue_keys.VLAN_KEY, 'data': data_to_queue }) queue_manager.send() self.save() except Exception, e: self.log.error(u'Error disabling Vlan.: %s' % e) raise VlanErrorV3(u'Error disabling Vlan.') finally: if locks_list: # Destroy locks destroy_lock(locks_list)
# def get_networks_related(self, eqpts=None, has_netv4=True, has_netv6=True, # exclude_current=True): # if not eqpts: # eqpts = self.get_eqpt() # vlan_model = get_model('vlan', 'Vlan') # vlans_env_eqpt = vlan_model.objects.filter( # # get vlans of environment or environment assoc # ambiente__equipamentoambiente__equipamento__in=eqpts # ).filter( # # get vlans with customized vrfs # Q(vrfvlanequipment__vrf__in=self.get_vrf()) | # # get vlans using vrf of environment # Q(ambiente__default_vrf__in=self.get_vrf()) # ).distinct() # if exclude_current: # vlans_env_eqpt = vlans_env_eqpt.exclude( # # exclude current vlan # id=self.id # ) # vlans_env_eqpt = vlans_env_eqpt.distinct() # self.log.debug('Query vlans: %s' % vlans_env_eqpt.query) # netv4 = list() # if has_netv4: # netv4 = reduce(list.__add__, [ # list(vlan_env.networkipv4_set.all()) # for vlan_env in vlans_env_eqpt if vlan_env.networkipv4_set.all()], []) # netv6 = list() # if has_netv6: # netv6 = reduce(list.__add__, [ # list(vlan_env.networkipv6_set.all()) # for vlan_env in vlans_env_eqpt if vlan_env.networkipv6_set.all()], []) # return netv4, netv6
[docs] def validate_network(self): configs = self.ambiente.configs.all() netv4 = self.networkipv4_set.filter() netv6 = self.networkipv6_set.filter() self.allow_networks_environment(configs, netv4, netv6) netv4, netv6 = network.get_networks_related( vrfs=self.get_vrf(), eqpts=self.get_eqpt(), exclude=self.id) netv4_env_format = [IPNetwork(net.networkv4) for net in netv4] netv6_env_format = [IPNetwork(net.networkv6) for net in netv6] netv4_format = [IPNetwork(net.networkv4) for net in self.networkipv4_set.all()] netv6_format = [IPNetwork(net.networkv6) for net in self.networkipv6_set.all()] network.verify_networks(netv4_format, netv4_env_format) network.verify_networks(netv6_format, netv6_env_format)
[docs] def allow_networks_environment(self, configs, netv4, netv6): """ Verify if networksv4 and networksv6 are permitted in environment by way configs settings. """ for net in netv4: configsv4 = configs.filter( ip_config__type='v4' ) nts = [IPNetwork(config.ip_config.subnet) for config in configsv4] net_ip = [IPNetwork(net.networkv4)] if not network.verify_intersect(nts, net_ip)[0]: msg = 'Network can not inserted in environment {} because ' \ 'network {} are in out of the range of allowed networks.' msg = msg.format(self.ambiente.name, net.networkv4) self.log.error(msg) raise VlanErrorV3(msg) for net in netv6: configsv6 = configs.filter( ip_config__type='v6' ) nts = [IPNetwork(config.ip_config.subnet) for config in configsv6] net_ip = [IPNetwork(net.networkv6)] if not network.verify_intersect(nts, net_ip)[0]: msg = 'Network can not inserted in environment {} because ' \ 'network {} are in out of the range of allowed networks.' msg = msg.format(self.ambiente.name, net.networkv6) self.log.error(msg) raise VlanErrorV3(msg)
[docs] def allocate_vlan(self): """Create a Vlan with the new Model The fields num_vlan, acl_file_name, acl_valida and ativada will be generated automatically @return: nothing """ if (self.ambiente.min_num_vlan_1 and self.ambiente.max_num_vlan_1) or \ (self.ambiente.min_num_vlan_2 and self.ambiente.max_num_vlan_2): min_num_01 = self.ambiente.min_num_vlan_1 \ if self.ambiente.min_num_vlan_1 and self.ambiente.max_num_vlan_1 \ else self.ambiente.min_num_vlan_2 max_num_01 = self.ambiente.max_num_vlan_1 \ if self.ambiente.min_num_vlan_1 and self.ambiente.max_num_vlan_1 \ else self.ambiente.max_num_vlan_2 min_num_02 = self.ambiente.min_num_vlan_2 \ if self.ambiente.min_num_vlan_2 and self.ambiente.max_num_vlan_2 \ else self.ambiente.min_num_vlan_1 max_num_02 = self.ambiente.max_num_vlan_2 \ if self.ambiente.min_num_vlan_2 and self.ambiente.max_num_vlan_2 \ else self.ambiente.max_num_vlan_1 else: min_num_01 = MIN_VLAN_NUMBER_01 max_num_01 = MAX_VLAN_NUMBER_01 min_num_02 = MIN_VLAN_NUMBER_02 max_num_02 = MAX_VLAN_NUMBER_02 # Calculate Number VLAN self.num_vlan = self.calculate_vlan_number_v3(min_num_01, max_num_01) if self.num_vlan is None: self.num_vlan = self.calculate_vlan_number_v3( min_num_02, max_num_02) if self.num_vlan is None: raise VlanNumberNotAvailableError( None, u'Number VLAN unavailable for environment %d.' % self.ambiente.id)
[docs] def calculate_vlan_number_v3(self, min_num, max_num, list_available=False): """Caculate if has a number available in range (min_num/max_num) to specified environment @param min_num: Minimum number that the vlan can be created. @param max_num: Maximum number that the vlan can be created. @param list_available: If = True, return the list of numbers availables @return: None when hasn't a number available | num_vlan when found a number available """ interval = range(min_num, max_num + 1) # Vlan numbers in interval in the same environment vlan_numbers_in_interval = self.search_vlan_numbers( self.ambiente_id, min_num, max_num) # Find equipment's ids from environmnet that is 'switches', # 'roteadores' or 'balanceadores' id_equipamentos = self.get_eqpt() # Vlan numbers in others environment but in environment that has # equipments found in before filter ('switches', 'roteadores' or # 'balanceadores') vlans_others_environments = Vlan.objects.exclude( ambiente__id=self.ambiente_id ).filter( ambiente__equipamentoambiente__equipamento__id__in=id_equipamentos ).values_list('num_vlan', flat=True) # Clean duplicates numbers and update merge 'vlan_numbers_in_interval' # with 'vlans_others_environments' vlan_numbers_in_interval = set(vlan_numbers_in_interval) vlan_numbers_in_interval.update(vlans_others_environments) self.log.debug('Interval: %s.', interval) self.log.debug('VLANs in interval: %s.', vlan_numbers_in_interval) diff_set = set(interval) - set(vlan_numbers_in_interval) self.log.debug('Difference in the lists: %s.', diff_set) if list_available: return diff_set for num_vlan in diff_set: return num_vlan return None