Source code for networkapi.api_pools.facade.facade_v1

# -*- coding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging

from django.conf import settings
from django.core.exceptions import MultipleObjectsReturned
from django.core.exceptions import ObjectDoesNotExist
from django.db import transaction

from networkapi.ambiente.models import Ambiente
from networkapi.api_pools import exceptions
from networkapi.api_pools.models import OptionPool
from networkapi.api_pools.models import OptionPoolEnvironment
from networkapi.healthcheckexpect.models import Healthcheck
from networkapi.infrastructure.script_utils import exec_script
from networkapi.infrastructure.script_utils import ScriptError
from networkapi.ip.models import Ip
from networkapi.ip.models import Ipv6
from networkapi.requisicaovips.models import ServerPool
from networkapi.requisicaovips.models import ServerPoolMember
from networkapi.util import is_valid_int_greater_zero_param
from networkapi.util import is_valid_list_int_greater_zero_param

log = logging.getLogger(__name__)


# Todo
# Not to be used alone like this
# User has to specifically choose an existing healthcheck in order to use the same healthcheck
# between pools
[docs]def get_or_create_healthcheck(user, healthcheck_expect, healthcheck_type, healthcheck_request, healthcheck_destination, identifier=''): try: # Query HealthCheck table for one equal this if identifier == '': hc = Healthcheck.objects.get(healthcheck_expect=healthcheck_expect, healthcheck_type=healthcheck_type, healthcheck_request=healthcheck_request, destination=healthcheck_destination) else: hc = Healthcheck.objects.get(identifier=identifier, healthcheck_expect=healthcheck_expect, healthcheck_type=healthcheck_type, healthcheck_request=healthcheck_request, destination=healthcheck_destination) # Else, add a new one except ObjectDoesNotExist: hc = Healthcheck(identifier=identifier, healthcheck_type=healthcheck_type, healthcheck_request=healthcheck_request, healthcheck_expect=healthcheck_expect, destination=healthcheck_destination) hc.save() # Get the fisrt occureny and warn if redundant HCs are present except MultipleObjectsReturned: log.warning( 'Multiple healthcheck entries found for the given parameters') if identifier == '': hc = Healthcheck.objects.filter(healthcheck_expect=healthcheck_expect, healthcheck_type=healthcheck_type, healthcheck_request=healthcheck_request, destination=healthcheck_destination).order_by('id')[0] else: hc = Healthcheck.objects.filter(identifier=identifier, healthcheck_expect=healthcheck_expect, healthcheck_type=healthcheck_type, healthcheck_request=healthcheck_request, destination=healthcheck_destination).order_by('id')[0] return hc
[docs]def save_server_pool(user, id, identifier, default_port, hc, env, balancing, maxconn, id_pool_member, servicedownaction): # Save Server pool old_healthcheck = None if id: sp = ServerPool.objects.get(id=id) # store old healthcheck,lb method and service-down-action old_servicedownaction = sp.servicedownaction old_identifier = sp.identifier old_healthcheck = Healthcheck.objects.get(id=sp.healthcheck.id) old_lb_method = sp.lb_method old_maxconn = sp.default_limit # validate change of environment if sp.environment and sp.environment.id != env.id: validate_change_of_environment(id_pool_member, sp) # Pool already created, it is not possible to change Pool Identifier if(old_identifier != identifier and sp.pool_created): raise exceptions.CreatedPoolIdentifierException() update_pool_fields(default_port, env, identifier, old_healthcheck, old_lb_method, old_maxconn, sp, user) update_pool_maxconn(maxconn, old_maxconn, sp, user) apply_health_check(hc, old_healthcheck, sp, user) update_load_balancing_method(balancing, old_lb_method, sp, user) apply_service_down_action( old_servicedownaction, servicedownaction, sp, user) else: sp = ServerPool(identifier=identifier, default_port=default_port, healthcheck=hc, environment=env, pool_created=False, lb_method=balancing, default_limit=maxconn, servicedownaction=servicedownaction) sp.save() return sp, (old_healthcheck.id if old_healthcheck else None)
[docs]def update_pool_fields(default_port, env, identifier, old_healthcheck, old_lb_method, old_maxconn, sp, user): sp.default_port = default_port sp.environment = env sp.default_limit = old_maxconn sp.healthcheck = old_healthcheck sp.lb_method = old_lb_method sp.identifier = identifier sp.save()
[docs]def validate_change_of_environment(id_pool_member, sp): if sp.pool_created: raise exceptions.UpdateEnvironmentPoolCreatedException() del_smp = sp.serverpoolmember_set.exclude(id__in=id_pool_member) vip = sp.vipporttopool_set.count() if vip > 0: raise exceptions.UpdateEnvironmentVIPException() if len(del_smp) > 0: raise exceptions.UpdateEnvironmentServerPoolMemberException()
[docs]def update_pool_maxconn(maxconn, old_maxconn, sp, user): sp.default_limit = maxconn sp.save() # If pool member exists, checks if all of them have the same maxconn # before changing its default maxconn if(len(sp.serverpoolmember_set.all()) > 0): if(old_maxconn != sp.default_limit and sp.pool_created): for serverpoolmember in sp.serverpoolmember_set.all(): if serverpoolmember.limit != old_maxconn: raise exceptions.ScriptAlterLimitPoolDiffMembersException() else: serverpoolmember.limit = maxconn serverpoolmember.save() transaction.commit() command = settings.POOL_MANAGEMENT_LIMITS % (sp.id) code, _, _ = exec_script(command) if code != 0: sp.default_limit = old_maxconn for serverpoolmember in sp.serverpoolmember_set.all(): serverpoolmember.limit = old_maxconn serverpoolmember.save() sp.save() transaction.commit() raise exceptions.ScriptAlterLimitPoolException()
[docs]def apply_health_check(hc, old_healthcheck, sp, user): # Applies new healthcheck in pool sp.healthcheck = hc sp.save() if (old_healthcheck.id != hc.id and sp.pool_created): transaction.commit() command = settings.POOL_HEALTHCHECK % (sp.id) code, _, _ = exec_script(command) if code != 0: sp.healthcheck = old_healthcheck sp.save() transaction.commit() raise exceptions.ScriptCreatePoolException()
[docs]def apply_service_down_action(old_servicedownaction, servicedownaction, sp, user): # Applies new service-down-action in pool sp.servicedownaction = servicedownaction sp.save() if (old_servicedownaction != sp.servicedownaction and sp.pool_created): transaction.commit() command = settings.POOL_SERVICEDOWNACTION % (sp.id) code, _, _ = exec_script(command) if code != 0: sp.servicedownaction = old_servicedownaction sp.save() transaction.commit() raise exceptions.ScriptAlterServiceDownActionException()
[docs]def update_load_balancing_method(balancing, old_lb_method, sp, user): sp.lb_method = balancing sp.save() if (old_lb_method != sp.lb_method and sp.pool_created): transaction.commit() command = settings.POOL_MANAGEMENT_LB_METHOD % (sp.id) code, _, _ = exec_script(command) if code != 0: sp.lb_method = old_lb_method sp.save() transaction.commit() raise exceptions.ScriptCreatePoolException()
[docs]def prepare_to_save_reals(ip_list_full, ports_reals, nome_equips, priorities, weight, id_pool_member, id_equips): list_server_pool_member = list() if id_pool_member: invalid_ports_real = [ i for i in ports_reals if int(i) > 65535 or int(i) < 1] invalid_priority = [ i for i in priorities if int(i) > 4294967295 or int(i) < 0] if invalid_priority: raise exceptions.InvalidRealPoolException( 'O valor da Prioridade deve estar entre 0 e 4294967295.') if invalid_ports_real: raise exceptions.InvalidRealPoolException( 'O número da porta deve estar entre 1 e 65535.') if len(id_equips) != len(id_pool_member): raise exceptions.InvalidRealPoolException( 'Quantidade de portas e equipamento difere.') for i in range(0, len(ip_list_full)): for j in range(0, len(ip_list_full)): if i == j: pass elif ports_reals[i] == ports_reals[j] and ip_list_full[i].get('id', '') == ip_list_full[j].get('id', ''): raise exceptions.InvalidRealPoolException( 'Ips com portas iguais.') for i in range(0, len(id_pool_member)): list_server_pool_member.append({'id': ip_list_full[i].get('id', '') if ip_list_full[i] else '', 'ip': ip_list_full[i].get('ip', '') if ip_list_full[i] else '', 'port_real': ports_reals[i], 'nome_equips': nome_equips[i], 'priority': priorities[i], 'weight': weight[i], 'id_pool_member': id_pool_member[i], }) return list_server_pool_member
[docs]def save_server_pool_member(user, pool, list_server_pool_member): list_pool_member = list() old_priorities_list = list() pool_members_to_be_removed = get_pool_members_to_be_removed( list_server_pool_member) remove_pool_members(pool_members_to_be_removed, pool, user) if list_server_pool_member: apply_new_priorities = False for dic in list_server_pool_member: ip_object, ipv6_object = get_ip_objects(dic) pool_member_id = dic['id_pool_member'] if pool_member_id: pool_member = ServerPoolMember.objects.get(id=pool_member_id) old_member_priority = pool_member.priority old_priorities_list.append(old_member_priority) update_pool_member( pool, pool_member, dic, ip_object, ipv6_object, user) if(old_member_priority != pool_member.priority and pool.pool_created): apply_new_priorities = True else: pool_member = ServerPoolMember() update_pool_member( pool, pool_member, dic, ip_object, ipv6_object, user) pool_member.save() old_priorities_list.append(dic['priority']) # execute script to create real if pool already created # commits transaction. Rolls back if script returns error if pool.pool_created: ip_id = ip_object and ip_object.id or ipv6_object and ipv6_object.id deploy_pool_member_config( ip_id, pool.id, dic['port_real'], pool_member, user) list_pool_member.append(pool_member) # Applies new priority in pool - only 1 script run for all members if(apply_new_priorities): apply_priorities(list_pool_member, old_priorities_list, pool, user) return list_pool_member
[docs]def update_pool_member(pool, pool_member, dic, ip_object, ipv6_object, user): pool_member.server_pool = pool pool_member.limit = pool.default_limit pool_member.ip = ip_object pool_member.ipv6 = ipv6_object pool_member.identifier = dic['nome_equips'] pool_member.weight = dic['weight'] pool_member.priority = dic['priority'] pool_member.port_real = dic['port_real'] pool_member.save()
[docs]def get_ip_objects(dic): ip_object = None ipv6_object = None if len(dic['ip']) <= 15: ip_object = Ip.get_by_pk(dic['id']) else: ipv6_object = Ipv6.get_by_pk(dic['id']) return ip_object, ipv6_object
[docs]def get_pool_members_to_be_removed(list_server_pool_member): # Remove empty values from list return [x['id_pool_member'] for x in list_server_pool_member if x['id_pool_member'] != '']
[docs]def remove_pool_members(id_pool_member_noempty, sp, user): # exclue server pool member del_smp = sp.serverpoolmember_set.exclude(id__in=id_pool_member_noempty) if del_smp: for obj in del_smp: obj.delete() # execute script remove real if pool already created # commit transaction after each successful script call if sp.pool_created: command = settings.POOL_REAL_REMOVE % ( obj.server_pool_id, obj.ip_id if obj.ip else obj.ipv6_id, obj.port_real) code, _, _ = exec_script(command) if code != 0: raise exceptions.ScriptCreatePoolException() transaction.commit()
[docs]def deploy_pool_member_config(id_ip, id_pool, port_ip, spm, user): transaction.commit() # def prepare_and_save(self, server_pool, ip, ip_type, priority, weight, port_real, user, commit=False): # spm.prepare_and_save(sp, ip_object, IP_VERSION.IPv4[1], dic['priority'], dic['weight'], dic['port_real'], user, True) command = settings.POOL_REAL_CREATE % (id_pool, id_ip, port_ip) code, _, _ = exec_script(command) if code != 0: spm.delete() transaction.commit() raise exceptions.ScriptCreatePoolException()
# if sp.healthcheck_id: # spm.healthcheck = sp.healthcheck
[docs]def apply_priorities(list_pool_member, old_priorities_list, sp, user): transaction.commit() command = settings.POOL_MEMBER_PRIORITIES % (sp.id) code, _, _ = exec_script(command) if code != 0: for i in range(0, len(old_priorities_list)): list_pool_member[i].priority = old_priorities_list[i] list_pool_member[i].save() transaction.commit() raise exceptions.ScriptAlterPriorityPoolMembersException()
[docs]def exec_script_check_poolmember_by_pool(pool_id): # execute script check status real command = settings.POOL_REAL_CHECK_BY_POOL % (pool_id) status_code, stdout, stderr = exec_script(command) if status_code != 0: raise exceptions.ScriptCheckStatusPoolMemberException() return stdout
[docs]def manager_pools(request): """ Manager Status Pool Members Enable/Disabled By Pool :param request: HttpRequest """ try: pool_id = request.DATA.get('server_pool_id') pool_members = request.DATA.get('server_pool_members', []) # List to validate pool member status valid_status = [0, 1, False, True] pool_members_id = [member.get('id') for member in pool_members] if not is_valid_int_greater_zero_param(pool_id): raise exceptions.InvalidIdPoolException() # Validate pool members id is_valid_list_int_greater_zero_param(pool_members_id) pool_obj = ServerPool.objects.get(id=pool_id) related_pool_members = pool_obj.serverpoolmember_set.order_by('id') received_pool_members = ServerPoolMember.objects.filter( id__in=pool_members_id).order_by('id') relates = list(related_pool_members) receives = list(received_pool_members) if relates != receives: raise exceptions.InvalidIdPoolMemberException( u'Required All Pool Members By Pool') for member in pool_members: member_id = member.get('id') member_status = member.get('status') if member_status not in valid_status: raise exceptions.InvalidStatusPoolMemberException() server_pool_member = ServerPoolMember.objects.get(id=member_id) server_pool_member.status = member_status server_pool_member.save(request.user, commit=True) # Execute Script To Set Status command = settings.POOL_MANAGEMENT_MEMBERS_STATUS % pool_id code, _, _ = exec_script(command) if code != 0: raise exceptions.ScriptManagementPoolException() except (exceptions.ScriptManagementPoolException, ScriptError), exception: # Rollback for old_member in related_pool_members: old_member.save(request.user, commit=True) raise exception
[docs]def save_option_pool(user, type, description): """if id: sp = OptionPool.objects.get(id=id) sp.type = type sp.description = description sp.save() else:""" sp = OptionPool(type=type, name=description) sp.save() return sp
[docs]def update_option_pool(user, option_id, type, description): sp = OptionPool.objects.get(id=option_id) sp.type = type sp.name = description sp.save() return sp
[docs]def delete_option_pool(user, option_id): pool_option = OptionPool.objects.get(id=option_id) environment_options = OptionPoolEnvironment.objects.all() environment_options = environment_options.filter(option=option_id) for eop in environment_options: eop.delete() pool_option.delete() return option_id
[docs]def save_environment_option_pool(user, option_id, environment_id): op = OptionPool.objects.get(id=option_id) env = Ambiente.objects.get(id=environment_id) # log.warning("objetos buscados %s %s", serializer_options.data, serializer_env.data) ope = OptionPoolEnvironment() ope.environment = env ope.option = op ope.save() return ope
[docs]def update_environment_option_pool(user, environment_option_id, option_id, environment_id): ope = OptionPoolEnvironment.objects.get(id=environment_option_id) op = OptionPool.objects.get(id=option_id) env = Ambiente.objects.get(id=environment_id) ope.option = op ope.environment = env ope.save() return ope
[docs]def delete_environment_option_pool(user, environment_option_id): ope = OptionPoolEnvironment.objects.get(id=environment_option_id) ope.delete() return environment_option_id