Browse Source

Merge branch 'main' into records-rfc-test

pull/930/head
Ross McFarland 3 years ago
committed by GitHub
parent
commit
437e3a6ca2
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 70 additions and 59 deletions
  1. +3
    -3
      README.md
  2. +2
    -2
      octodns/cmds/args.py
  3. +2
    -4
      octodns/cmds/report.py
  4. +1
    -1
      octodns/processor/acme.py
  5. +1
    -1
      octodns/processor/ownership.py
  6. +1
    -1
      octodns/provider/base.py
  7. +1
    -1
      octodns/provider/plan.py
  8. +2
    -2
      octodns/provider/yaml.py
  9. +24
    -24
      octodns/record/__init__.py
  10. +6
    -8
      octodns/source/axfr.py
  11. +2
    -4
      octodns/source/envvar.py
  12. +2
    -2
      octodns/source/tinydns.py
  13. +9
    -2
      octodns/zone.py
  14. +2
    -2
      tests/helpers.py
  15. +2
    -2
      tests/test_octodns_provider_base.py
  16. +10
    -0
      tests/test_octodns_zone.py

+ 3
- 3
README.md View File

@ -1,4 +1,4 @@
<img src="https://raw.githubusercontent.com/octodns/octodns/master/docs/logos/octodns-logo.png?" alt="OctoDNS Logo" height=251 width=404>
<img src="https://raw.githubusercontent.com/octodns/octodns/main/docs/logos/octodns-logo.png?" alt="OctoDNS Logo" height=251 width=404>
## DNS as code - Tools for managing DNS across multiple providers
@ -178,7 +178,7 @@ After the reviews it's time to branch deploy the change.
![Output of a deployment command](/docs/assets/deploy.png)
If that goes smoothly, you again see the expected changes, and verify them with `dig` and/or `octodns-report` you're good to hit the merge button. If there are problems you can quickly do a `.deploy dns/master` to go back to the previous state.
If that goes smoothly, you again see the expected changes, and verify them with `dig` and/or `octodns-report` you're good to hit the merge button. If there are problems you can quickly do a `.deploy dns/main` to go back to the previous state.
### Bootstrapping config files
@ -378,7 +378,7 @@ If you know of any other resources, please do let us know!
OctoDNS is licensed under the [MIT license](LICENSE).
The MIT license grant is not for GitHub's trademarks, which include the logo designs. GitHub reserves all trademark and copyright rights in and to all GitHub trademarks. GitHub's logos include, for instance, the stylized designs that include "logo" in the file title in the following folder: https://github.com/octodns/octodns/tree/master/docs/logos/
The MIT license grant is not for GitHub's trademarks, which include the logo designs. GitHub reserves all trademark and copyright rights in and to all GitHub trademarks. GitHub's logos include, for instance, the stylized designs that include "logo" in the file title in the following folder: https://github.com/octodns/octodns/tree/main/docs/logos/
GitHub® and its stylized versions and the Invertocat mark are GitHub's Trademarks or registered Trademarks. When using GitHub's logos, be sure to follow the GitHub logo guidelines.


+ 2
- 2
octodns/cmds/args.py View File

@ -18,7 +18,7 @@ class ArgumentParser(_Base):
'''
def __init__(self, *args, **kwargs):
super(ArgumentParser, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def parse_args(self, default_log_level=INFO):
version = f'octoDNS {__VERSION__}'
@ -50,7 +50,7 @@ class ArgumentParser(_Base):
'--debug', action='store_true', default=False, help=_help
)
args = super(ArgumentParser, self).parse_args()
args = super().parse_args()
self._setup_logging(args, default_log_level)
return args


+ 2
- 4
octodns/cmds/report.py View File

@ -16,13 +16,11 @@ from octodns.manager import Manager
class AsyncResolver(Resolver):
def __init__(self, num_workers, *args, **kwargs):
super(AsyncResolver, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
self.executor = ThreadPoolExecutor(max_workers=num_workers)
def query(self, *args, **kwargs):
return self.executor.submit(
super(AsyncResolver, self).query, *args, **kwargs
)
return self.executor.submit(super().query, *args, **kwargs)
def main():


+ 1
- 1
octodns/processor/acme.py View File

@ -25,7 +25,7 @@ class AcmeMangingProcessor(BaseProcessor):
- acme
...
'''
super(AcmeMangingProcessor, self).__init__(name)
super().__init__(name)
self._owned = set()


+ 1
- 1
octodns/processor/ownership.py View File

@ -15,7 +15,7 @@ from .base import BaseProcessor
# and thus "own" them going forward.
class OwnershipProcessor(BaseProcessor):
def __init__(self, name, txt_name='_owner', txt_value='*octodns*'):
super(OwnershipProcessor, self).__init__(name)
super().__init__(name)
self.txt_name = txt_name
self.txt_value = txt_value
self._txt_values = [txt_value]


+ 1
- 1
octodns/provider/base.py View File

@ -17,7 +17,7 @@ class BaseProvider(BaseSource):
delete_pcent_threshold=Plan.MAX_SAFE_DELETE_PCENT,
strict_supports=False,
):
super(BaseProvider, self).__init__(id)
super().__init__(id)
self.log.debug(
'__init__: id=%s, apply_disabled=%s, '
'update_pcent_threshold=%.2f, '


+ 1
- 1
octodns/provider/plan.py View File

@ -136,7 +136,7 @@ class _PlanOutput(object):
class PlanLogger(_PlanOutput):
def __init__(self, name, level='info'):
super(PlanLogger, self).__init__(name)
super().__init__(name)
try:
self.level = {
'debug': DEBUG,


+ 2
- 2
octodns/provider/yaml.py View File

@ -128,7 +128,7 @@ class YamlProvider(BaseProvider):
enforce_order,
populate_should_replace,
)
super(YamlProvider, self).__init__(id, *args, **kwargs)
super().__init__(id, *args, **kwargs)
self.directory = directory
self.default_ttl = default_ttl
self.enforce_order = enforce_order
@ -311,7 +311,7 @@ class SplitYamlProvider(YamlProvider):
CATCHALL_RECORD_NAMES = ('*', '')
def __init__(self, id, directory, extension='.', *args, **kwargs):
super(SplitYamlProvider, self).__init__(id, directory, *args, **kwargs)
super().__init__(id, directory, *args, **kwargs)
self.extension = extension
def _zone_directory(self, zone):


+ 24
- 24
octodns/record/__init__.py View File

@ -32,7 +32,7 @@ class Create(Change):
CLASS_ORDERING = 1
def __init__(self, new):
super(Create, self).__init__(None, new)
super().__init__(None, new)
def __repr__(self, leader=''):
source = self.new.source.id if self.new.source else ''
@ -58,7 +58,7 @@ class Delete(Change):
CLASS_ORDERING = 0
def __init__(self, existing):
super(Delete, self).__init__(existing, None)
super().__init__(existing, None)
def __repr__(self, leader=''):
return f'Delete {self.existing}'
@ -80,7 +80,7 @@ class ValidationError(RecordException):
return f'Invalid record {idna_decode(fqdn)}\n - {reasons}'
def __init__(self, fqdn, reasons):
super(Exception, self).__init__(self.build_message(fqdn, reasons))
super().__init__(self.build_message(fqdn, reasons))
self.fqdn = fqdn
self.reasons = reasons
@ -373,7 +373,7 @@ class GeoValue(EqualityTupleMixin):
class ValuesMixin(object):
@classmethod
def validate(cls, name, fqdn, data):
reasons = super(ValuesMixin, cls).validate(name, fqdn, data)
reasons = super().validate(name, fqdn, data)
values = data.get('values', data.get('value', []))
@ -390,7 +390,7 @@ class ValuesMixin(object):
return {'ttl': rr.ttl, 'type': rr._type, 'values': values}
def __init__(self, zone, name, data, source=None):
super(ValuesMixin, self).__init__(zone, name, data, source=source)
super().__init__(zone, name, data, source=source)
try:
values = data['values']
except KeyError:
@ -400,10 +400,10 @@ class ValuesMixin(object):
def changes(self, other, target):
if self.values != other.values:
return Update(self, other)
return super(ValuesMixin, self).changes(other, target)
return super().changes(other, target)
def _data(self):
ret = super(ValuesMixin, self)._data()
ret = super()._data()
if len(self.values) > 1:
values = [getattr(v, 'data', v) for v in self.values if v]
if len(values) > 1:
@ -441,7 +441,7 @@ class _GeoMixin(ValuesMixin):
@classmethod
def validate(cls, name, fqdn, data):
reasons = super(_GeoMixin, cls).validate(name, fqdn, data)
reasons = super().validate(name, fqdn, data)
try:
geo = dict(data['geo'])
for code, values in geo.items():
@ -452,7 +452,7 @@ class _GeoMixin(ValuesMixin):
return reasons
def __init__(self, zone, name, data, *args, **kwargs):
super(_GeoMixin, self).__init__(zone, name, data, *args, **kwargs)
super().__init__(zone, name, data, *args, **kwargs)
try:
self.geo = dict(data['geo'])
except KeyError:
@ -461,7 +461,7 @@ class _GeoMixin(ValuesMixin):
self.geo[code] = GeoValue(code, values)
def _data(self):
ret = super(_GeoMixin, self)._data()
ret = super()._data()
if self.geo:
geo = {}
for code, value in self.geo.items():
@ -473,7 +473,7 @@ class _GeoMixin(ValuesMixin):
if target.SUPPORTS_GEO:
if self.geo != other.geo:
return Update(self, other)
return super(_GeoMixin, self).changes(other, target)
return super().changes(other, target)
def __repr__(self):
if self.geo:
@ -482,13 +482,13 @@ class _GeoMixin(ValuesMixin):
f'<{klass} {self._type} {self.ttl}, {self.decoded_fqdn}, '
f'{self.values}, {self.geo}>'
)
return super(_GeoMixin, self).__repr__()
return super().__repr__()
class ValueMixin(object):
@classmethod
def validate(cls, name, fqdn, data):
reasons = super(ValueMixin, cls).validate(name, fqdn, data)
reasons = super().validate(name, fqdn, data)
reasons.extend(
cls._value_type.validate(data.get('value', None), cls._type)
)
@ -505,16 +505,16 @@ class ValueMixin(object):
}
def __init__(self, zone, name, data, source=None):
super(ValueMixin, self).__init__(zone, name, data, source=source)
super().__init__(zone, name, data, source=source)
self.value = self._value_type.process(data['value'])
def changes(self, other, target):
if self.value != other.value:
return Update(self, other)
return super(ValueMixin, self).changes(other, target)
return super().changes(other, target)
def _data(self):
ret = super(ValueMixin, self)._data()
ret = super()._data()
if self.value:
ret['value'] = getattr(self.value, 'data', self.value)
return ret
@ -640,7 +640,7 @@ class _DynamicMixin(object):
@classmethod
def validate(cls, name, fqdn, data):
reasons = super(_DynamicMixin, cls).validate(name, fqdn, data)
reasons = super().validate(name, fqdn, data)
if 'dynamic' not in data:
return reasons
@ -799,7 +799,7 @@ class _DynamicMixin(object):
return reasons
def __init__(self, zone, name, data, *args, **kwargs):
super(_DynamicMixin, self).__init__(zone, name, data, *args, **kwargs)
super().__init__(zone, name, data, *args, **kwargs)
self.dynamic = {}
@ -829,7 +829,7 @@ class _DynamicMixin(object):
self.dynamic = _Dynamic(pools, parsed)
def _data(self):
ret = super(_DynamicMixin, self)._data()
ret = super()._data()
if self.dynamic:
ret['dynamic'] = self.dynamic._data()
return ret
@ -838,7 +838,7 @@ class _DynamicMixin(object):
if target.SUPPORTS_DYNAMIC:
if self.dynamic != other.dynamic:
return Update(self, other)
return super(_DynamicMixin, self).changes(other, target)
return super().changes(other, target)
def __repr__(self):
# TODO: improve this whole thing, we need multi-line...
@ -856,7 +856,7 @@ class _DynamicMixin(object):
f'<{klass} {self._type} {self.ttl}, {self.decoded_fqdn}, '
f'{values}, {self.dynamic}>'
)
return super(_DynamicMixin, self).__repr__()
return super().__repr__()
class _TargetValue(str):
@ -984,7 +984,7 @@ class AliasRecord(ValueMixin, Record):
reasons = []
if name != '':
reasons.append('non-root ALIAS not allowed')
reasons.extend(super(AliasRecord, cls).validate(name, fqdn, data))
reasons.extend(super().validate(name, fqdn, data))
return reasons
@ -1094,7 +1094,7 @@ class CnameRecord(_DynamicMixin, ValueMixin, Record):
reasons = []
if name == '':
reasons.append('root CNAME not allowed')
reasons.extend(super(CnameRecord, cls).validate(name, fqdn, data))
reasons.extend(super().validate(name, fqdn, data))
return reasons
@ -2136,7 +2136,7 @@ class SrvRecord(ValuesMixin, Record):
reasons = []
if not cls._name_re.match(name):
reasons.append('invalid name for SRV record')
reasons.extend(super(SrvRecord, cls).validate(name, fqdn, data))
reasons.extend(super().validate(name, fqdn, data))
return reasons


+ 6
- 8
octodns/source/axfr.py View File

@ -39,7 +39,7 @@ class AxfrBaseSource(BaseSource):
)
def __init__(self, id):
super(AxfrBaseSource, self).__init__(id)
super().__init__(id)
def populate(self, zone, target=False, lenient=False):
self.log.debug(
@ -65,9 +65,7 @@ class AxfrSourceException(Exception):
class AxfrSourceZoneTransferFailed(AxfrSourceException):
def __init__(self):
super(AxfrSourceZoneTransferFailed, self).__init__(
'Unable to Perform Zone Transfer'
)
super().__init__('Unable to Perform Zone Transfer')
class AxfrSource(AxfrBaseSource):
@ -83,7 +81,7 @@ class AxfrSource(AxfrBaseSource):
def __init__(self, id, master):
self.log = logging.getLogger(f'AxfrSource[{id}]')
self.log.debug('__init__: id=%s, master=%s', id, master)
super(AxfrSource, self).__init__(id)
super().__init__(id)
self.master = master
def zone_records(self, zone):
@ -111,12 +109,12 @@ class ZoneFileSourceException(Exception):
class ZoneFileSourceNotFound(ZoneFileSourceException):
def __init__(self):
super(ZoneFileSourceNotFound, self).__init__('Zone file not found')
super().__init__('Zone file not found')
class ZoneFileSourceLoadFailure(ZoneFileSourceException):
def __init__(self, error):
super(ZoneFileSourceLoadFailure, self).__init__(str(error))
super().__init__(str(error))
class ZoneFileSource(AxfrBaseSource):
@ -148,7 +146,7 @@ class ZoneFileSource(AxfrBaseSource):
file_extension,
check_origin,
)
super(ZoneFileSource, self).__init__(id)
super().__init__(id)
self.directory = directory
self.file_extension = file_extension
self.check_origin = check_origin


+ 2
- 4
octodns/source/envvar.py View File

@ -11,9 +11,7 @@ class EnvVarSourceException(Exception):
class EnvironmentVariableNotFoundException(EnvVarSourceException):
def __init__(self, data):
super(EnvironmentVariableNotFoundException, self).__init__(
f'Unknown environment variable {data}'
)
super().__init__(f'Unknown environment variable {data}')
class EnvVarSource(BaseSource):
@ -73,7 +71,7 @@ class EnvVarSource(BaseSource):
name,
ttl,
)
super(EnvVarSource, self).__init__(id)
super().__init__(id)
self.envvar = variable
self.name = name
self.ttl = ttl


+ 2
- 2
octodns/source/tinydns.py View File

@ -23,7 +23,7 @@ class TinyDnsBaseSource(BaseSource):
split_re = re.compile(r':+')
def __init__(self, id, default_ttl=3600):
super(TinyDnsBaseSource, self).__init__(id)
super().__init__(id)
self.default_ttl = default_ttl
def _data_for_A(self, _type, records):
@ -239,7 +239,7 @@ class TinyDnsFileSource(TinyDnsBaseSource):
directory,
default_ttl,
)
super(TinyDnsFileSource, self).__init__(id, default_ttl)
super().__init__(id, default_ttl)
self.directory = directory
self._cache = None


+ 9
- 2
octodns/zone.py View File

@ -41,7 +41,8 @@ class Zone(object):
self._root_ns = None
# optional leading . to match empty hostname
# optional trailing . b/c some sources don't have it on their fqdn
self._name_re = re.compile(fr'\.?{name}?$')
self._utf8_name_re = re.compile(fr'\.?{idna_decode(name)}?$')
self._idna_name_re = re.compile(fr'\.?{self.name}?$')
# Copy-on-write semantics support, when `not None` this property will
# point to a location with records for this `Zone`. Once `hydrated`
@ -63,7 +64,13 @@ class Zone(object):
return self._root_ns
def hostname_from_fqdn(self, fqdn):
return self._name_re.sub('', fqdn)
try:
fqdn.encode('ascii')
# it's non-idna or idna encoded
return self._idna_name_re.sub('', idna_encode(fqdn))
except UnicodeEncodeError:
# it has utf8 chars
return self._utf8_name_re.sub('', fqdn)
def add_record(self, record, replace=False, lenient=False):
if self._origin:


+ 2
- 2
tests/helpers.py View File

@ -95,7 +95,7 @@ class TemporaryDirectory(object):
class WantsConfigProcessor(BaseProcessor):
def __init__(self, name, some_config):
super(WantsConfigProcessor, self).__init__(name)
super().__init__(name)
class PlannableProvider(BaseProvider):
@ -106,7 +106,7 @@ class PlannableProvider(BaseProvider):
SUPPORTS = set(('A', 'AAAA', 'TXT'))
def __init__(self, *args, **kwargs):
super(PlannableProvider, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def populate(self, zone, source=False, target=False, lenient=False):
pass


+ 2
- 2
tests/test_octodns_provider_base.py View File

@ -53,7 +53,7 @@ class HelperProvider(BaseProvider):
class TrickyProcessor(BaseProcessor):
def __init__(self, name, add_during_process_target_zone):
super(TrickyProcessor, self).__init__(name)
super().__init__(name)
self.add_during_process_target_zone = add_during_process_target_zone
self.reset()
@ -640,7 +640,7 @@ class TestBaseProvider(TestCase):
def __init__(self, **kwargs):
self.log = MagicMock()
super(MinimalProvider, self).__init__('minimal', **kwargs)
super().__init__('minimal', **kwargs)
normal = MinimalProvider(strict_supports=False)
# Should log and not expect


+ 10
- 0
tests/test_octodns_zone.py View File

@ -47,10 +47,16 @@ class TestZone(TestCase):
('foo.bar', 'foo.bar.unit.tests'),
('foo.unit.tests', 'foo.unit.tests.unit.tests.'),
('foo.unit.tests', 'foo.unit.tests.unit.tests'),
# if we pass utf8 we get utf8
('déjà', 'déjà.unit.tests'),
('déjà.foo', 'déjà.foo.unit.tests'),
('bar.déjà', 'bar.déjà.unit.tests'),
('bar.déjà.foo', 'bar.déjà.foo.unit.tests'),
# if we pass idna we get idna
('xn--dj-kia8a', 'xn--dj-kia8a.unit.tests'),
('xn--dj-kia8a.foo', 'xn--dj-kia8a.foo.unit.tests'),
('bar.xn--dj-kia8a', 'bar.xn--dj-kia8a.unit.tests'),
('bar.xn--dj-kia8a.foo', 'bar.xn--dj-kia8a.foo.unit.tests'),
):
self.assertEqual(hostname, zone.hostname_from_fqdn(fqdn))
@ -68,6 +74,10 @@ class TestZone(TestCase):
('déjà.foo', 'déjà.foo.grüßen.de'),
('bar.déjà', 'bar.déjà.grüßen.de'),
('bar.déjà.foo', 'bar.déjà.foo.grüßen.de'),
('xn--dj-kia8a', 'xn--dj-kia8a.xn--gren-wna7o.de'),
('xn--dj-kia8a.foo', 'xn--dj-kia8a.foo.xn--gren-wna7o.de'),
('bar.xn--dj-kia8a', 'bar.xn--dj-kia8a.xn--gren-wna7o.de'),
('bar.xn--dj-kia8a.foo', 'bar.xn--dj-kia8a.foo.xn--gren-wna7o.de'),
):
self.assertEqual(hostname, zone.hostname_from_fqdn(fqdn))


Loading…
Cancel
Save