# -*- 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