Exemple #1
0
    def _any_response(self, params):
        """Generate a response to ANY/A query.

        See polaris_health.state to_dist_dict() methods for the distribution
        state implementation details.
        """
        qname = params['qname'].lower()

        # get a pool associated with the qname
        pool_name = STATE['globalnames'][qname]['pool_name']
        pool = STATE['pools'][pool_name]

        # use the _default distribution table by default
        dist_table = pool['dist_tables']['_default']

        # pool is UP
        if pool['status']:
            # if using a topology based method, check if we have a distribution
            # table in the same region, if so - use it
            if pool['lb_method'] == 'twrr':

                # we'll log the time it takes to perfom a topology lookup
                t = time.time()

                # lookup the client's region, get_region() will
                # return None if the region cannot be determined
                region = topology.get_region(params['remote'],
                                             config.TOPOLOGY_MAP)

                # log the time taken to perform the lookup
                self.log.append(
                    'get_region() time taken: {:.6f}'.format(time.time() - t))

                # log client's region
                self.log.append('client region: {}'.format(region))

                # if we have a region table corresponding
                # to the client's region - use it
                if region in pool['dist_tables']:
                    dist_table = pool['dist_tables'][region]

        # pool is DOWN
        else:
            # if fallback is set to "refuse", refuse the query
            # (SOA response must return False as well)
            if pool['fallback'] == 'refuse':
                self.result = False
                return

            # otherwise(fallback is "any") use the _default distribution table

        # log the distribution table used
        self.log.append('dist table used: {}'.format(json.dumps(dist_table)))

        # determine how many records to return
        # which is the minimum of the dist table's num_unique_addrs and
        # the pool's max_addrs_returned
        if dist_table['num_unique_addrs'] <= pool['max_addrs_returned']:
            num_records_return = dist_table['num_unique_addrs']
        else:
            num_records_return = pool['max_addrs_returned']

        # if we don't have anything to return(all member weights may have
        # been set of 0), set the result to false
        if num_records_return == 0:
            self.result = False
            return

        # add records to the response
        for i in range(num_records_return):
            # add record to the response
            self.add_record(
                qtype='A',
                # use the original qname from the parameters dict
                qname=params['qname'],
                content=dist_table['rotation'][dist_table['index']],
                ttl=STATE['globalnames'][qname]['ttl'])

            # increase index
            dist_table['index'] += 1
            # set the index to 0 if we reached the end of the rotation list
            if dist_table['index'] >= len(dist_table['rotation']):
                dist_table['index'] = 0
Exemple #2
0
    def _any_response(self, params):
        """Generate a response to ANY/A query.

        See polaris_health.state to_dist_dict() methods for the distribution
        state implementation details.
        """
        qname = params['qname'].lower()

        # get a pool associated with the qname
        pool_name = self._state['globalnames'][qname]['pool_name']
        pool = self._state['pools'][pool_name]
       
        # use the _default distribution table by default
        dist_table = pool['dist_tables']['_default']

        ##################
        ### pool is UP ###
        ##################
        if pool['status']:
            # if using a topology based method, check if we have a distribution
            # table in the same region, if so - use it
            if pool['lb_method'] == 'twrr':

                # we'll log the time it takes to perfom a topology lookup
                t = time.time()

                # lookup the client's region, get_region() will
                # return None if the region cannot be determined
                region = topology.get_region(params['remote'], 
                                             config.TOPOLOGY_MAP)

                # log the time taken to perform the lookup
                self.log.append(
                    'get_region() time taken: {:.6f}'.format(time.time() - t))

                # log client's region
                self.log.append('client region: {}'.format(region))

                # if we have a region table corresponding 
                # to the client's region - use it
                if region in pool['dist_tables']:
                    dist_table = pool['dist_tables'][region]

        ####################
        ### pool is DOWN ###
        ####################
        else:
            # if fallback is set to "refuse", refuse the query
            # (SOA response must return False as well)
            if pool['fallback'] == 'refuse':
                self.result = False
                return

            # otherwise(fallback is "any") use the _default distribution table

        # log the distribution table used
        self.log.append('dist table used: {}'
                        .format(json.dumps(dist_table)))

        # determine how many records to return
        # which is the minimum of the dist table's num_unique_addrs and 
        # the pool's max_addrs_returned
        if dist_table['num_unique_addrs'] <= pool['max_addrs_returned']: 
            num_records_return = dist_table['num_unique_addrs']
        else:    
            num_records_return = pool['max_addrs_returned']

        # if we don't have anything to return(all member weights may have
        # been set of 0), set the result to false
        if num_records_return == 0:
            self.result = False
            return

        ### add records to the response ###
        for i in range(num_records_return):
            # add record to the response
            self.add_record(qtype='A',
                            # use the original qname from the parameters dict        
                            qname=params['qname'],
                            content=dist_table['rotation'][dist_table['index']],
                            ttl=self._state['globalnames'][qname]['ttl'])    

            # increase index
            dist_table['index'] += 1
            # set the index to 0 if we reached the end of the rotation list
            if dist_table['index'] >= len(dist_table['rotation']):
                dist_table['index'] = 0
Exemple #3
0
    def from_config_dict(cls, pool_name, obj):
        """Build a Pool object from a config dict

        args:
            pool_name: string, pool_name of the pool
            obj: dict, config dict
        """
        #################################
        ### pool mandatory parameters ###
        #################################

        ### monitor
        if obj['monitor'] not in monitors.registered:
            log_msg = 'unknown monitor "{}"'.format(obj['monitor'])
            LOG.error(log_msg)
            raise Error(log_msg)
        else:
            monitor_name = obj['monitor']

        if 'monitor_params' in obj:
            if not obj['monitor_params']:
                log_msg = 'monitor_params should not be empty'
                LOG.error(log_msg)
                raise Error(log_msg)

            monitor_params = obj['monitor_params']
        else:
            monitor_params = {}
 
        monitor = monitors.registered[monitor_name](**monitor_params)

        ### lb_method
        lb_method = obj['lb_method']

        ### members
        members = []

        # validate "members" key is present and not empty
        if not 'members' in obj or not obj['members']:
            log_msg = ('configuration dictionary must contain '
                       'a non-empty "members" list')    
            LOG.error(log_msg)
            raise Error(log_msg)

        for member_obj in obj['members']:
            # ensure a member with the same IP doesn't exist already 
            for _m in members:
                if member_obj['ip'] == _m.ip:
                    log_msg = 'duplicate member IP {}'.format(member_obj['ip'])
                    LOG.error(log_msg)
                    raise Error(log_msg)

            ### member optional parameters ###
            member_optional_params = {}

            ### region
            # if topology lb method is used - set region
            if lb_method == 'twrr':
                region = topology.get_region(
                    member_obj['ip'], config.TOPOLOGY_MAP)
                if not region:
                    log_msg  = ('unable to determine region for member {}({})'
                                .format(member_obj['ip'], member_obj['name'])) 
                    LOG.error(log_msg)
                    raise Error(log_msg)
                member_optional_params['region'] = region

            ### monitor_ip
            if 'monitor_ip' in member_obj:
                member_optional_params['monitor_ip'] = member_obj['monitor_ip']

            _m = PoolMember(ip=member_obj['ip'], 
                            name=member_obj['name'], 
                            weight=member_obj['weight'],
                            **member_optional_params)
            members.append(_m)

        ################################
        ### pool optional parameters ###
        ################################
        pool_optional_params = {}

        ### fallback
        if 'fallback' in obj:
            pool_optional_params['fallback'] = obj['fallback']

        ### max_addrs_returned
        if 'max_addrs_returned' in obj:
            pool_optional_params['max_addrs_returned'] = \
                obj['max_addrs_returned']

        # return Pool object
        return cls(name=pool_name,
                   monitor=monitor,
                   lb_method=lb_method,
                   members=members,
                   **pool_optional_params)
Exemple #4
0
    def from_config_dict(cls, pool_name, obj):
        """Build a Pool object from a config dict

        args:
            pool_name: string, pool_name of the pool
            obj: dict, config dict
        """
        ############################
        ### mandatory parameters ###
        ############################

        ### monitor
        if obj['monitor'] not in monitors.registered:
            log_msg = 'unknown monitor "{}"'.format(obj['monitor'])
            LOG.error(log_msg)
            raise Error(log_msg)
        else:
            monitor_name = obj['monitor']

        if 'monitor_params' in obj:
            if not obj['monitor_params']:
                log_msg = 'monitor_params should not be empty'
                LOG.error(log_msg)
                raise Error(log_msg)

            monitor_params = obj['monitor_params']
        else:
            monitor_params = {}
                 
        monitor = monitors.registered[monitor_name](**monitor_params)

        ### lb_method
        lb_method = obj['lb_method']

        ### members
        members = []

        # validate "members" key is present and not empty
        if not 'members' in obj or not obj['members']:
            log_msg = ('configuration dictionary must contain '
                       'a non-empty "members" list')    
            LOG.error(log_msg)
            raise Error(log_msg)

        for member_obj in obj['members']:
            # ensure a member with the same IP doesn't exist already 
            for _m in members:
                if member_obj['ip'] == _m.ip:
                    log_msg = 'duplicate member IP {}'.format(member_obj['ip'])
                    LOG.error(log_msg)
                    raise Error(log_msg)

            region = None
            # if topology lb method is used - set region on the pool member
            if lb_method == 'twrr':
                region = topology.get_region(
                    member_obj['ip'], config.TOPOLOGY_MAP)
                if not region:
                    log_msg  = ('unable to determine region for member {}({})'
                                .format(member_obj['ip'], member_obj['name'])) 
                    LOG.error(log_msg)
                    raise Error(log_msg)

            _m = PoolMember(ip=member_obj['ip'], 
                            name=member_obj['name'], 
                            weight=member_obj['weight'],
                            region=region)
            members.append(_m)

        ###########################
        ### optional parameters ###
        ###########################
        pool_optional_params = {}

        ### fallback
        if 'fallback' in obj:
            pool_optional_params['fallback'] = obj['fallback']

        ### max_addrs_returned
        if 'max_addrs_returned' in obj:
            pool_optional_params['max_addrs_returned'] = \
                obj['max_addrs_returned']

        # return Pool object
        return cls(name=pool_name,
                   monitor=monitor,
                   lb_method=lb_method,
                   members=members,
                   **pool_optional_params)