mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Merge remote-tracking branch 'origin/main' into dynamic-zones
This commit is contained in:
5
.github/workflows/modules.yml
vendored
5
.github/workflows/modules.yml
vendored
@@ -37,7 +37,10 @@ jobs:
|
|||||||
- octodns/octodns-selectel
|
- octodns/octodns-selectel
|
||||||
- octodns/octodns-transip
|
- octodns/octodns-transip
|
||||||
- octodns/octodns-ultra
|
- octodns/octodns-ultra
|
||||||
- sukiyaki/octodns-netbox
|
# has been failing for a while now and afaict not related to octoDNS
|
||||||
|
# changes commenting out on 2023-07-30, will check on it again in at
|
||||||
|
# some point in the future and either re-enable or delete it.
|
||||||
|
#- sukiyaki/octodns-netbox
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@master
|
- uses: actions/checkout@master
|
||||||
- name: Setup python
|
- name: Setup python
|
||||||
|
16
CHANGELOG.md
16
CHANGELOG.md
@@ -1,3 +1,19 @@
|
|||||||
|
## v1.0.0 - 2023-07-30 - The One
|
||||||
|
|
||||||
|
1.0 marks a point at which we can formally deprecate things that will be
|
||||||
|
going away with 2.0 more than specific functionality that has been added or
|
||||||
|
having reached a notable level of stability (beyond what is normal.) It is also
|
||||||
|
long (years) overdue.
|
||||||
|
|
||||||
|
#### Noteworthy changes
|
||||||
|
|
||||||
|
* `geo` records are deprecated.
|
||||||
|
|
||||||
|
#### Stuff
|
||||||
|
|
||||||
|
* Removal of a Python 3.7 specific import work-around now that it's no longer an
|
||||||
|
active/supported version. Also bumps required minimum version of Python 3.8
|
||||||
|
|
||||||
## v1.0.0.rc1 - 2023-07-20 - The last one before the 1s
|
## v1.0.0.rc1 - 2023-07-20 - The last one before the 1s
|
||||||
|
|
||||||
* Record and Zone validation now ensures there's no whitespace in names
|
* Record and Zone validation now ensures there's no whitespace in names
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
'OctoDNS: DNS as code - Tools for managing DNS across multiple providers'
|
'OctoDNS: DNS as code - Tools for managing DNS across multiple providers'
|
||||||
|
|
||||||
__VERSION__ = '1.0.0rc1'
|
__VERSION__ = '1.0.0'
|
||||||
|
@@ -101,9 +101,3 @@ class ArgumentParser(_Base):
|
|||||||
# we still want plans to come out during quite so set the plan
|
# we still want plans to come out during quite so set the plan
|
||||||
# logger output to info in case the PlanLogger is being used
|
# logger output to info in case the PlanLogger is being used
|
||||||
getLogger('Plan').setLevel(INFO)
|
getLogger('Plan').setLevel(INFO)
|
||||||
|
|
||||||
# TODO: these should move out of octoDNS core...
|
|
||||||
# boto is noisy, set it to warn
|
|
||||||
getLogger('botocore').level = WARNING
|
|
||||||
# DynectSession is noisy too
|
|
||||||
getLogger('DynectSession').level = WARNING
|
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from importlib.metadata import PackageNotFoundError
|
||||||
|
from importlib.metadata import version as module_version
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import environ
|
from os import environ
|
||||||
from sys import stdout
|
from sys import stdout
|
||||||
@@ -19,18 +21,6 @@ from .record import Record
|
|||||||
from .yaml import safe_load
|
from .yaml import safe_load
|
||||||
from .zone import Zone
|
from .zone import Zone
|
||||||
|
|
||||||
# TODO: this can go away once we no longer support python 3.7
|
|
||||||
try: # pragma: no cover
|
|
||||||
from importlib.metadata import PackageNotFoundError
|
|
||||||
from importlib.metadata import version as module_version
|
|
||||||
except ModuleNotFoundError: # pragma: no cover
|
|
||||||
|
|
||||||
class PackageNotFoundError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def module_version(*args, **kargs):
|
|
||||||
raise PackageNotFoundError('placeholder')
|
|
||||||
|
|
||||||
|
|
||||||
class _AggregateTarget(object):
|
class _AggregateTarget(object):
|
||||||
id = 'aggregate'
|
id = 'aggregate'
|
||||||
|
@@ -79,7 +79,6 @@ class Plan(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def raise_if_unsafe(self):
|
def raise_if_unsafe(self):
|
||||||
# TODO: what is safe really?
|
|
||||||
if (
|
if (
|
||||||
self.existing
|
self.existing
|
||||||
and len(self.existing.records) >= self.MIN_EXISTING_RECORDS
|
and len(self.existing.records) >= self.MIN_EXISTING_RECORDS
|
||||||
|
@@ -141,6 +141,9 @@ class _GeoMixin(ValuesMixin):
|
|||||||
reasons = super().validate(name, fqdn, data)
|
reasons = super().validate(name, fqdn, data)
|
||||||
try:
|
try:
|
||||||
geo = dict(data['geo'])
|
geo = dict(data['geo'])
|
||||||
|
cls.log.warning(
|
||||||
|
'NOTICE: `geo` record support is deprecated and should be migrated to `dynamic` records'
|
||||||
|
)
|
||||||
for code, values in geo.items():
|
for code, values in geo.items():
|
||||||
reasons.extend(GeoValue._validate_geo(code))
|
reasons.extend(GeoValue._validate_geo(code))
|
||||||
reasons.extend(cls._value_type.validate(values, cls._type))
|
reasons.extend(cls._value_type.validate(values, cls._type))
|
||||||
|
@@ -161,8 +161,12 @@ class Zone(object):
|
|||||||
|
|
||||||
self._records[record.name].discard(record)
|
self._records[record.name].discard(record)
|
||||||
|
|
||||||
# TODO: delete this
|
# TODO: delete this at v2.0.0rc0
|
||||||
_remove_record = remove_record
|
def _remove_record(self, record):
|
||||||
|
self.log.warning(
|
||||||
|
'_remove_record: method has been deprecated, used remove_record instead'
|
||||||
|
)
|
||||||
|
return self.remove_record(record)
|
||||||
|
|
||||||
def changes(self, desired, target):
|
def changes(self, desired, target):
|
||||||
self.log.debug('changes: zone=%s, target=%s', self, target)
|
self.log.debug('changes: zone=%s, target=%s', self, target)
|
||||||
|
2
setup.py
2
setup.py
@@ -99,7 +99,7 @@ setup(
|
|||||||
long_description_content_type='text/markdown',
|
long_description_content_type='text/markdown',
|
||||||
name='octodns',
|
name='octodns',
|
||||||
packages=find_packages(),
|
packages=find_packages(),
|
||||||
python_requires='>=3.6',
|
python_requires='>=3.8',
|
||||||
tests_require=tests_require,
|
tests_require=tests_require,
|
||||||
url='https://github.com/octodns/octodns',
|
url='https://github.com/octodns/octodns',
|
||||||
version=version(),
|
version=version(),
|
||||||
|
@@ -139,32 +139,31 @@ class TestYamlProvider(TestCase):
|
|||||||
with open(dynamic_yaml_file) as fh:
|
with open(dynamic_yaml_file) as fh:
|
||||||
data = safe_load(fh.read())
|
data = safe_load(fh.read())
|
||||||
|
|
||||||
# make sure new dynamic records made the trip
|
# make sure dynamic records made the trip
|
||||||
dyna = data.pop('a')
|
dyna = data.pop('a')
|
||||||
self.assertTrue('values' in dyna)
|
self.assertTrue('values' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
# TODO:
|
|
||||||
|
|
||||||
# make sure new dynamic records made the trip
|
# make sure dynamic records made the trip
|
||||||
dyna = data.pop('aaaa')
|
dyna = data.pop('aaaa')
|
||||||
self.assertTrue('values' in dyna)
|
self.assertTrue('values' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
|
|
||||||
dyna = data.pop('cname')
|
dyna = data.pop('cname')
|
||||||
self.assertTrue('value' in dyna)
|
self.assertTrue('value' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
|
|
||||||
dyna = data.pop('real-ish-a')
|
dyna = data.pop('real-ish-a')
|
||||||
self.assertTrue('values' in dyna)
|
self.assertTrue('values' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
|
|
||||||
dyna = data.pop('simple-weighted')
|
dyna = data.pop('simple-weighted')
|
||||||
self.assertTrue('value' in dyna)
|
self.assertTrue('value' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
|
|
||||||
dyna = data.pop('pool-only-in-fallback')
|
dyna = data.pop('pool-only-in-fallback')
|
||||||
self.assertTrue('value' in dyna)
|
self.assertTrue('value' in dyna)
|
||||||
# self.assertTrue('dynamic' in dyna)
|
self.assertTrue('dynamic' in dyna)
|
||||||
|
|
||||||
# make sure nothing is left
|
# make sure nothing is left
|
||||||
self.assertEqual([], list(data.keys()))
|
self.assertEqual([], list(data.keys()))
|
||||||
|
@@ -213,15 +213,22 @@ class TestRecordGeoCodes(TestCase):
|
|||||||
self.assertTrue(c >= b)
|
self.assertTrue(c >= b)
|
||||||
|
|
||||||
def test_validation(self):
|
def test_validation(self):
|
||||||
Record.new(
|
with self.assertLogs('Record', level='WARNING') as cm:
|
||||||
self.zone,
|
Record.new(
|
||||||
'',
|
self.zone,
|
||||||
{
|
'',
|
||||||
'geo': {'NA': ['1.2.3.5'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
|
{
|
||||||
'type': 'A',
|
'geo': {'NA': ['1.2.3.5'], 'NA-US': ['1.2.3.5', '1.2.3.6']},
|
||||||
'ttl': 600,
|
'type': 'A',
|
||||||
'value': '1.2.3.4',
|
'ttl': 600,
|
||||||
},
|
'value': '1.2.3.4',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
[
|
||||||
|
'WARNING:Record:NOTICE: `geo` record support is deprecated and should be migrated to `dynamic` records'
|
||||||
|
],
|
||||||
|
cm.output,
|
||||||
)
|
)
|
||||||
|
|
||||||
# invalid ip address
|
# invalid ip address
|
||||||
|
@@ -125,7 +125,7 @@ class TestZone(TestCase):
|
|||||||
# add a record, delete a record -> [Delete, Create]
|
# add a record, delete a record -> [Delete, Create]
|
||||||
c = ARecord(before, 'c', {'ttl': 42, 'value': '1.1.1.1'})
|
c = ARecord(before, 'c', {'ttl': 42, 'value': '1.1.1.1'})
|
||||||
after.add_record(c)
|
after.add_record(c)
|
||||||
after._remove_record(b)
|
after.remove_record(b)
|
||||||
self.assertEqual(after.records, set([a, c]))
|
self.assertEqual(after.records, set([a, c]))
|
||||||
changes = before.changes(after, target)
|
changes = before.changes(after, target)
|
||||||
self.assertEqual(2, len(changes))
|
self.assertEqual(2, len(changes))
|
||||||
@@ -154,6 +154,14 @@ class TestZone(TestCase):
|
|||||||
self.assertFalse(changed.changes(update.new, target))
|
self.assertFalse(changed.changes(update.new, target))
|
||||||
update.__repr__()
|
update.__repr__()
|
||||||
|
|
||||||
|
def test_deprecated__remove_record(self):
|
||||||
|
zone = Zone('unit.tests.', [])
|
||||||
|
a = ARecord(zone, 'a', {'ttl': 42, 'value': '1.1.1.1'})
|
||||||
|
zone.add_record(a)
|
||||||
|
self.assertEqual({a}, zone.records)
|
||||||
|
zone._remove_record(a)
|
||||||
|
self.assertEqual(set(), zone.records)
|
||||||
|
|
||||||
def test_unsupporting(self):
|
def test_unsupporting(self):
|
||||||
class NoAaaaProvider(object):
|
class NoAaaaProvider(object):
|
||||||
id = 'no-aaaa'
|
id = 'no-aaaa'
|
||||||
|
Reference in New Issue
Block a user