diff --git a/octodns/source/tinydns.py b/octodns/source/tinydns.py index 100f482..55a5eaf 100755 --- a/octodns/source/tinydns.py +++ b/octodns/source/tinydns.py @@ -13,6 +13,17 @@ from ..record import Record from .base import BaseSource +def _unique(values): + try: + # this will work if they're simple strings + return list(set(values)) + except TypeError: + pass + # if they're dictionaries it's a bit more involved since dict's aren't + # hashable, based on https://stackoverflow.com/a/38521207 + return [dict(s) for s in set(frozenset(v.items()) for v in values)] + + class TinyDnsBaseSource(BaseSource): SUPPORTS_GEO = False SUPPORTS_DYNAMIC = False @@ -387,7 +398,7 @@ class TinyDnsBaseSource(BaseSource): def _process_symbols(self, zone, symbols, arpa): types = defaultdict(lambda: defaultdict(list)) - ttls = defaultdict(lambda: defaultdict(lambda: self.default_ttl)) + ttls = defaultdict(dict) for symbol, names in symbols.items(): records_for = self.SYMBOL_MAP.get(symbol, None) if not records_for: @@ -404,8 +415,10 @@ class TinyDnsBaseSource(BaseSource): # remove the zone name name = zone.hostname_from_fqdn(name) types[_type][name].extend(values) - # last one wins - ttls[_type][name] = ttl + # first non-default wins, if we never see anything we'll + # just use the default below + if ttl != self.default_ttl: + ttls[_type][name] = ttl return types, ttls @@ -440,9 +453,12 @@ class TinyDnsBaseSource(BaseSource): # it to the zone for _type, names in types.items(): for name, values in names.items(): - data = {'ttl': ttls[_type][name], 'type': _type} + data = { + 'ttl': ttls[_type].get(name, self.default_ttl), + 'type': _type, + } if len(values) > 1: - data['values'] = values + data['values'] = _unique(values) else: data['value'] = values[0] record = Record.new(zone, name, data, lenient=lenient) diff --git a/tests/zones/tinydns/example.com b/tests/zones/tinydns/example.com index 9cb1eb8..301269f 100755 --- a/tests/zones/tinydns/example.com +++ b/tests/zones/tinydns/example.com @@ -5,6 +5,8 @@ # Multi-value A +example.com:10.2.3.4:30 +example.com.:10.2.3.5:30 +# duplicate value should be ignored ++example.com:10.2.3.4 Ccname.other.foo:www.other.foo @@ -65,5 +67,8 @@ Ccname.other.foo:www.other.foo # SRV S_a._tcp.example.com:56.57.58.59:target:8888 S_a._tcp.example.com::target.somewhere.else:8080:10:50:43 -# TODO: add an IP so it tries to create a record that already exists -S_b._tcp.example.com::target.srv.example.com.:9999 +# will try and re-create an already existing A with the same IP, should be a +# noop +S_b._tcp.example.com:56.57.58.59:target.srv.example.com.:9999 +# complete duplicate should be ignored +S_b._tcp.example.com:56.57.58.59:target.srv.example.com.:9999