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
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
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)
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)