Source code for networkapi.plugins.F5.util

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

import copy
import logging
from functools import wraps

import bigsuds
import ipaddress

from networkapi.plugins import exceptions as base_exceptions
from networkapi.plugins.F5 import lb

log = logging.getLogger(__name__)


########################################
# Decorators
########################################
[docs]def logger(func): @wraps(func) def inner(self, *args, **kwargs): log.info('%s.%s: %s,%s' % (self.__class__.__name__, func.__name__, args, kwargs)) return func(self, *args, **kwargs) return inner
[docs]def transation(func): @wraps(func) def inner(self, *args, **kwargs): if not kwargs.__contains__('connection') or kwargs['connection']: try: access = args[0].get('access').filter( tipo_acesso__protocolo='https').uniqueResult() self._lb = lb.Lb(access.fqdn, access.user, access.password) if not kwargs.__contains__('transation') or kwargs['transation']: log.info('Transaction Started') with bigsuds.Transaction(self._lb._channel): return func(self, *args, **kwargs) else: return func(self, *args, **kwargs) except bigsuds.OperationFailed, e: log.error(e) raise base_exceptions.CommandErrorException(e) except Exception, e: log.error('Error %s' % e) raise base_exceptions.CommandErrorException(e) else: return func(self, *args, **kwargs) return inner
[docs]def connection(func): @wraps(func) def inner(self, *args, **kwargs): try: access = args[0].get('access').filter( tipo_acesso__protocolo='https').uniqueResult() self._lb = lb.Lb(access.fqdn, access.user, access.password) self._lb._channel.System.Session.set_transaction_timeout(60) return func(self, *args, **kwargs) except bigsuds.OperationFailed, e: log.error(e) raise base_exceptions.CommandErrorException(e) return inner
[docs]def connection_simple(func): @wraps(func) def inner(self, *args, **kwargs): try: access = args[0].get('access').filter( tipo_acesso__protocolo='https').uniqueResult() self._lb = lb.Lb(access.fqdn, access.user, access.password, False) return func(self, *args, **kwargs) except bigsuds.OperationFailed, e: log.error(e) raise base_exceptions.CommandErrorException(e) return inner
[docs]def get_status_name(status): try: return STATUS_POOL_MEMBER[status] except Exception: msg = 'Member status invalid: %s' % (status) log.error(msg) raise base_exceptions.NamePropertyInvalid(msg)
[docs]def get_method_name(lb_method): try: return LB_METHOD[lb_method] except Exception: msg = 'Member lb_method invalid: %s' % (lb_method) log.error(msg) raise base_exceptions.NamePropertyInvalid(msg)
[docs]def get_service_down_action_name(action): try: return SERVICE_DOWN_ACTION[action] except Exception: msg = '"%s" is not a valid value for Service Down Action' % (action) log.error(msg) raise base_exceptions.NamePropertyInvalid(msg)
[docs]def trata_param_pool(pools): pls = { 'pools_names': [], 'pools_lbmethod': [], 'pools_healthcheck': [], 'pools_actions': [], 'pools_confirm': { 'pools_names': [], 'members': [], 'monitor': [] }, 'pools_members': { 'members_new': [], 'members_remove': [], 'members': [], 'monitor': [], 'session': [], 'description': [], 'priority': [], 'weight': [], 'limit': [] } } for p in pools['pools']: pls['pools_names'].append(p['nome']) if p.get('lb_method'): pls['pools_lbmethod'].append( get_method_name(p['lb_method'])) if p.get('healthcheck') is not None: if p.get('healthcheck').get('new'): pls['pools_healthcheck'].append(p['healthcheck']) if p.get('action'): pls['pools_actions'].append( get_service_down_action_name(p['action'])) member_status_monitor = [] member_status_session = [] member_limit = [] member_priority = [] member_description = [] member_weight = [] member = [] member_new = [] member_remove = [] for pool_member in p['pools_members']: state = str(pool_member.get('member_status')) if pool_member.get('new'): node_port = { 'address': pool_member['ip'], 'port': pool_member['port']} member_new.append(node_port) if state == '7': if p['nome'] not in pls['pools_confirm']['pools_names']: pls['pools_confirm']['pools_names'].append(p['nome']) pls['pools_confirm']['members'].append(list()) pls['pools_confirm']['monitor'].append(list()) status_confirm = get_status_name(state) state = '2' idx = pls['pools_confirm']['pools_names'].index(p['nome']) pls['pools_confirm']['members'][idx].append(node_port) pls['pools_confirm']['monitor'][ idx].append(status_confirm['monitor']) if pool_member.get('member_status') is not None: status = get_status_name(state) member_status_monitor.append(status['monitor']) member_status_session.append(status['session']) if pool_member.get('limit') is not None: member_limit.append(pool_member['limit']) if pool_member.get('priority') is not None: member_priority.append(pool_member['priority']) if pool_member.get('identifier') is not None: member_description.append(pool_member['identifier']) if pool_member.get('weight') is not None: if p.get('lb_method') == 'weighted' and int(pool_member['weight']) > 0: member_weight.append(pool_member['weight']) else: member_weight.append('1') if not pool_member.get('remove'): member.append({ 'address': pool_member['ip'], 'port': pool_member['port']}) if pool_member.get('remove'): member_remove.append({ 'address': pool_member['ip'], 'port': pool_member['port']}) pls['pools_members']['monitor'].append(member_status_monitor) pls['pools_members']['session'].append(member_status_session) pls['pools_members']['limit'].append(member_limit) pls['pools_members']['priority'].append(member_priority) pls['pools_members']['description'].append(member_description) pls['pools_members']['weight'].append(member_weight) pls['pools_members']['members'].append(member) pls['pools_members']['members_new'].append(member_new) pls['pools_members']['members_remove'].append(member_remove) return pls
[docs]def trata_param_vip(vips): vips_filter = list() pool_filter = list() ids_pool_filter = list() vips_cache_filter = list() vips_cache_filter_to_delete = list() vips_cache_filter_to_insert = list() # when pool already created in eqpt pool_filter_created = list() ids_pool_filter_created = list() # to use in pool and port deleted(update vip) vips_filter_to_delete = list() pool_filter_to_delete = list() ids_pool_filter_to_delete = list() # to use in new pool or new port(update vip) vips_filter_to_insert = list() # pool_filter_to_insert = list() # ids_pool_filter_to_insert = list() for vip in vips['vips']: vp = copy.deepcopy(vip.get('vip_request')) ports = vp.get('ports') for pt in ports: vip_filter = dict() vip_request = copy.deepcopy(vp) port = copy.deepcopy(pt) dscp = vip_request['options']['dscp'] * 4 \ if vip_request['options']['dscp'] else 65535 conf = vip_request['conf']['conf'] address = vip_request['ipv4']['ip_formated'] \ if vip_request['ipv4'] else vip_request['ipv6']['ip_formated'] vip_filter['name'] = port['identifier'] address = str(ipaddress.ip_address(unicode(address))) vip_filter['address'] = address vip_filter['port'] = port['port'] vip_filter['optionsvip'] = vip_request['options'] # TCP or UDP vip_filter['optionsvip']['l4_protocol'] = \ port['options']['l4_protocol'] # Kind Layer of Application: HTTP, HTTPS, SSH, etc vip_filter['optionsvip']['l7_protocol'] = \ port['options']['l7_protocol'] # Value of cluster unit try: for keys in conf['keys']: cluster_unit = keys\ .get(vip_request['options']['cluster_unit'], None) # traffic-group-1 is default, so must be ignored if cluster_unit == 'traffic-group-1' or \ cluster_unit is None: cluster_unit = None break except Exception: cluster_unit = None pass vip_filter['optionsvip']['traffic_group'] = cluster_unit vip_filter['optionsvip_extended'] = conf['optionsvip_extended'] pools = port.get('pools') rules = dict() default_l7 = '' for pl in pools: pool = copy.deepcopy(pl) server_pool = pool.get('server_pool') pool_delete = False # Flag to delete port or pool in port # Pool to delete in put request of vip(when delete pool or # port) if pl.get('delete') or pt.get('delete'): pool_delete = True # Objects server_pool and ids to delete afterwards if server_pool.get('id') not in ids_pool_filter_to_delete: log.info('Pool to delete in equipment: %s' % server_pool) ids_pool_filter_to_delete.append(server_pool.get('id')) pool_filter_to_delete.append(server_pool) # # Pools to insert or to associate when id of internal control # # was changed. POST and DELETE always use this . else: # Pool not created yet in equipment if server_pool.get('id') not in ids_pool_filter and \ not server_pool.get('pool_created'): log.info('Pool to create in equipment: %s and' 'to need associate with vip' % server_pool) ids_pool_filter.append(server_pool.get('id')) pool_filter.append(server_pool) # Pool already created in equipment elif server_pool.get('id') not in ids_pool_filter_created and \ server_pool.get('pool_created'): log.info('Pool already created in equipment: %s' ', but to need associate with vip ' % server_pool) ids_pool_filter_created.append(server_pool.get('id')) pool_filter_created.append(server_pool) # Pools without delete if not pool_delete: name_pool = server_pool['nome'] # There is no l7 rule if pool.get('l7_rule') == 'default_vip': vip_filter['pool'] = name_pool vip_filter['optionsvip']['dscp'] = { 'value': dscp, 'pool_name': name_pool } # Default of l7 rule else: if pool.get('l7_rule') == 'default_glob': default_l7 = ' default {{ pool {0} }}\n'\ .format(name_pool) # l7 rule elif pool.get('l7_rule') == 'glob': rule = '"{0}"'.format(pool.get('l7_value')) order = pool.get('order', 'Z') key_rule = '{}_{}'.format(order, name_pool) if not rules.get(key_rule): rules[key_rule] = dict() rules[key_rule]['pool'] = name_pool rules[key_rule]['rule'] = list() rules[key_rule]['rule'].append(rule) # rules to create if rules: rule_l7_ln = '\n '.join([ '{0} {{\n pool {1}\n }}'.format( ' -\n '.join(rules[idx]['rule']), rules[idx]['pool'] ) for idx in sorted(rules) ]) rule_l7 = \ 'when HTTP_REQUEST {{\n' + \ ' switch -glob [HTTP::uri] {{\n' + \ ' {0}\n{1}' + \ ' }}\n' + \ ' }}' rule_l7 = rule_l7.format(rule_l7_ln, default_l7) vip_filter['pool_l7'] = rule_l7 # port(vip_port) to delete in update of vip if pt.get('delete'): vips_filter_to_delete.append(vip_filter) # port(vip_port) to insert in update of vip elif pt.get('insert'): vips_filter_to_insert.append(vip_filter) # vips to create/delete/update else: vips_filter.append(vip_filter) if vips.get('layers'): for vip_id in vips.get('layers'): for id_layer in vips.get('layers').get(vip_id): definitions = vips.get('layers').get( vip_id).get(id_layer).get('definitions') vip_request = vips.get('layers').get( vip_id).get(id_layer).get('vip_request') ports = vip_request.get('ports') for port in ports: vip_cache_filter = dict() address = vip_request['ipv4']['ip_formated'] \ if vip_request['ipv4'] else vip_request['ipv6']['ip_formated'] vip_cache_filter['pool'] = None vip_cache_filter['name'] = port['identifier'] address = str(ipaddress.ip_address(unicode(address))) vip_cache_filter['address'] = address vip_cache_filter['port'] = port['port'] vip_cache_filter['optionsvip'] = dict() vip_cache_filter['optionsvip_extended'] = dict() vip_cache_filter['optionsvip']['l4_protocol'] = \ port['options']['l4_protocol'] for definition in definitions.get(str(port['port'])): if definition.get('type') == 'pool': vip_cache_filter['pool'] = definition.get('value') if definition.get('type') == 'rule': if definition.get('value'): vip_cache_filter['rules'] = [ definition.get('value')] if definition.get('type') == 'profile': vip_cache_filter['optionsvip_extended'] = { 'requiments': [{ 'condicionals': [{ 'validations': [], 'use':[ definition ] }] }] } if definition.get('type') == 'traffic_group': if definition.get('value') == 'traffic-group-1': vip_cache_filter['optionsvip'][ 'traffic_group'] = None else: vip_cache_filter['optionsvip'][ 'traffic_group'] = definition.get('value') # port(vip_port) to delete in update of vip if port.get('delete'): vips_cache_filter_to_delete.append(vip_cache_filter) # port(vip_port) to insert in update of vip elif port.get('insert'): vips_cache_filter_to_insert.append(vip_cache_filter) # vips to create/delete/update else: vips_cache_filter.append(vip_cache_filter) # remove pools in both lists(to delete and to insert) to_delete = list( set(ids_pool_filter_to_delete) - set(ids_pool_filter_created) - set(ids_pool_filter) ) to_insert = list( set(ids_pool_filter) - set(ids_pool_filter_created) ) pool_filter_to_delete = [pool_del for pool_del in pool_filter_to_delete if pool_del.get('id') in to_delete] pool_filter_to_insert = [pool_ins for pool_ins in pool_filter if pool_ins.get('id') in to_insert] res_fil = { 'vips_filter': vips_filter, 'pool_filter': pool_filter, 'vips_cache_filter': vips_cache_filter, 'vips_cache_filter_to_delete': vips_cache_filter_to_delete, 'vips_cache_filter_to_insert': vips_cache_filter_to_insert, 'pool_filter_created': pool_filter_created, # used only in update of vips 'pool_filter_to_delete': pool_filter_to_delete, 'pool_filter_to_insert': pool_filter_to_insert, 'vips_filter_to_delete': vips_filter_to_delete, 'vips_filter_to_insert': vips_filter_to_insert, } return res_fil
[docs]def search_dict(mylist, lookup): for val in mylist: if lookup == val: return True return False
####################### # PROPERTIES DICT ####################### ######## # POOL ######## SERVICE_DOWN_ACTION = { 'reset': 'SERVICE_DOWN_ACTION_RESET', 'drop': 'SERVICE_DOWN_ACTION_DROP', 'reselect': 'SERVICE_DOWN_ACTION_RESELECT', 'none': 'SERVICE_DOWN_ACTION_NONE' } ############### # POOL MEMBER ############### # healthcheck+session enable/disable+user up/down(000 - 111 = 0 - 7) # 0 0 0 # | | \-- user up/user down (forcado a nao receber nem sessoes de persistencia) # | | 1/0 forcar disable do membro no pool (user up/down) # | \---- habilitar/desabilitar membro (session enable/session disable - # | nao recebe novas sessoes mas honra persistencia) # | 1/0 habilitar/desabilitar membro no pool para novas sessoes (session disable) # \------ status do healthcheck no LB, somente GET, nao e alterado # por usuario flag ignorada no PUT. # 1/0 status do healthcheck no LB member up/down STATUS_POOL_MEMBER = { '0': { 'monitor': 'STATE_DISABLED', 'session': 'STATE_DISABLED', 'healthcheck': 'STATE_DISABLED' }, '1': { 'monitor': 'STATE_ENABLED', 'session': 'STATE_DISABLED', 'healthcheck': 'STATE_DISABLED' }, '2': { 'monitor': 'STATE_DISABLED', 'session': 'STATE_ENABLED', 'healthcheck': 'STATE_DISABLED' }, '3': { 'monitor': 'STATE_ENABLED', 'session': 'STATE_ENABLED', 'healthcheck': 'STATE_DISABLED' }, '4': { 'monitor': 'STATE_DISABLED', 'session': 'STATE_DISABLED', 'healthcheck': 'STATE_ENABLED' }, '5': { 'monitor': 'STATE_ENABLED', 'session': 'STATE_DISABLED', 'healthcheck': 'STATE_ENABLED' }, '6': { 'monitor': 'STATE_DISABLED', 'session': 'STATE_ENABLED', 'healthcheck': 'STATE_ENABLED' }, '7': { 'monitor': 'STATE_ENABLED', 'session': 'STATE_ENABLED', 'healthcheck': 'STATE_ENABLED' } } LB_METHOD = { 'least-conn': 'LB_METHOD_LEAST_CONNECTION_MEMBER', 'round-robin': 'LB_METHOD_ROUND_ROBIN', 'weighted': 'LB_METHOD_RATIO_MEMBER', # '': 'LB_METHOD_LEAST_CONNECTION_MEMBER', # '': 'LB_METHOD_OBSERVED_MEMBER', # '': 'LB_METHOD_PREDICTIVE_MEMBER', # '': 'LB_METHOD_RATIO_NODE_ADDRESS', # '': 'LB_METHOD_LEAST_CONNECTION_NODE_ADDRESS', # '': 'LB_METHOD_FASTEST_NODE_ADDRESS', # '': 'LB_METHOD_OBSERVED_NODE_ADDRESS', # '': 'LB_METHOD_PREDICTIVE_NODE_ADDRESS', # '': 'LB_METHOD_DYNAMIC_RATIO', # '': 'LB_METHOD_FASTEST_APP_RESPONSE', # '': 'LB_METHOD_LEAST_SESSIONS', # '': 'LB_METHOD_DYNAMIC_RATIO_MEMBER', # '': 'LB_METHOD_L3_ADDR', # '': 'LB_METHOD_UNKNOWN', # '': 'LB_METHOD_WEIGHTED_LEAST_CONNECTION_MEMBER', # '': 'LB_METHOD_WEIGHTED_LEAST_CONNECTION_NODE_ADDRESS', # '': 'LB_METHOD_RATIO_SESSION', # '': 'LB_METHOD_RATIO_LEAST_CONNECTION_MEMBER', # '': 'LB_METHOD_RATIO_LEAST_CONNECTION_NODE_ADDRESS' }