diff --git a/octodns/provider/dyn.py b/octodns/provider/dyn.py index 7846bbb..684bbc8 100644 --- a/octodns/provider/dyn.py +++ b/octodns/provider/dyn.py @@ -237,6 +237,7 @@ class DynProvider(BaseProvider): 'OC': 16, # Continental Australia/Oceania 'AN': 17, # Continental Antarctica } + # Reverse of ^ REGION_CODES_LOOKUP = {code: geo for geo, code in REGION_CODES.items()} MONITOR_HEADER = 'User-Agent: Dyn Monitor' @@ -410,10 +411,9 @@ class DynProvider(BaseProvider): def _populate_geo_traffic_director(self, zone, fqdn, _type, td, rulesets, lenient): - # We start out with something that will always change show - # change in case this is a busted TD. This will prevent us from - # creating a duplicate td. We'll overwrite this with real data - # provide we have it + # We start out with something that will always show change in case this + # is a busted TD. This will prevent us from creating a duplicate td. + # We'll overwrite this with real data provided we have it geo = {} data = { 'geo': geo, @@ -489,6 +489,7 @@ class DynProvider(BaseProvider): label = response_pool.label if label == 'default': + # The default pool has the base record values default = data_for(_type, record_set.records) else: if label not in pools: @@ -496,6 +497,7 @@ class DynProvider(BaseProvider): # Note we'll have to set fallbacks as we go through rules # b/c we can't determine them here values = [value_for(_type, r) for r in record_set.records] + # Sort to ensure consistent ordering so we can compare them values.sort(key=_dynamic_value_sort_key) pools[label] = { 'values': values, @@ -506,16 +508,24 @@ class DynProvider(BaseProvider): def _populate_dynamic_rules(self, rulesets, pools): rules = [] + # Build the list of rules based on the rulesets for ruleset in rulesets: if ruleset.label.startswith('default:'): + # Ignore the default, it's implicit in our model continue num_pools = len(ruleset.response_pools) if num_pools > 0: + # Find the primary pool for this rule pool = ruleset.response_pools[0].label # TODO: verify pool exists if num_pools > 1: - # We have a fallback, record it in the approrpriate pool + # We have a fallback, record it in the approrpriate pool. + # Note we didn't have fallback info when we populated the + # pools above so we're filling that info in here. It's + # possible that rules will have disagreeing values for the + # fallbacks. That's annoying but a sync should fix it and + # match stuff up with the config. fallback = ruleset.response_pools[1].label # TODO: verify fallback exists if fallback != 'default': @@ -526,6 +536,8 @@ class DynProvider(BaseProvider): ruleset.label) continue + # OK we have the rule's pool info, record it and work on the rule's + # matching criteria rule = { 'pool': pool, } @@ -886,13 +898,17 @@ class DynProvider(BaseProvider): def _find_or_create_dynamic_pool(self, td, pools, label, _type, values, monitor_id=None, record_extras={}): + # Sort the values for consistent ordering so that we can compare values = sorted(values, key=_dynamic_value_sort_key) + # Ensure that weight is included and if not use the default values = map(lambda v: { 'value': v['value'], 'weight': v.get('weight', 1), }, values) + # Walk through our existing pools looking for a match we can use for pool in pools: + # It must have the same label if pool.label != label: continue try: @@ -900,13 +916,15 @@ class DynProvider(BaseProvider): except IndexError: # No values, can't match continue + # And the (sorted) values must match once converted for comparison + # purposes value_for = getattr(self, '_value_for_{}'.format(_type)) record_values = [value_for(_type, r) for r in records] if record_values == values: # it's a match return pool - # we need to create the pool + # We don't have this pool and thus need to create it records_for = getattr(self, '_dynamic_records_for_{}'.format(_type)) records = records_for(values, record_extras) record_set = DSFRecordSet(_type, label, @@ -1243,11 +1261,14 @@ class DynProvider(BaseProvider): new = change.new fqdn = new.fqdn _type = new._type + # Create a new traffic director label = '{}:{}'.format(fqdn, _type) node = DSFNode(new.zone.name, fqdn) td = TrafficDirector(label, ttl=new.ttl, nodes=[node], publish='Y') self.log.debug('_mod_dynamic_Create: td=%s', td.service_id) + # Sync up it's pools & rules self._mod_dynamic_rulesets(td, change) + # Store it for future reference self.traffic_directors[fqdn] = { _type: td }