1
0
mirror of https://github.com/github/octodns.git synced 2024-05-11 05:55:00 +00:00

Merge pull request #120 from github/threshold_overrides

add ability to configure update/delete thresholds
This commit is contained in:
Joe Williams
2017-10-10 15:07:39 -07:00
committed by GitHub
2 changed files with 79 additions and 7 deletions

View File

@@ -21,10 +21,14 @@ class Plan(object):
MAX_SAFE_DELETE_PCENT = .3 MAX_SAFE_DELETE_PCENT = .3
MIN_EXISTING_RECORDS = 10 MIN_EXISTING_RECORDS = 10
def __init__(self, existing, desired, changes): def __init__(self, existing, desired, changes,
update_pcent_threshold=MAX_SAFE_UPDATE_PCENT,
delete_pcent_threshold=MAX_SAFE_DELETE_PCENT):
self.existing = existing self.existing = existing
self.desired = desired self.desired = desired
self.changes = changes self.changes = changes
self.update_pcent_threshold = update_pcent_threshold
self.delete_pcent_threshold = delete_pcent_threshold
change_counts = { change_counts = {
'Create': 0, 'Create': 0,
@@ -55,14 +59,14 @@ class Plan(object):
update_pcent = self.change_counts['Update'] / existing_record_count update_pcent = self.change_counts['Update'] / existing_record_count
delete_pcent = self.change_counts['Delete'] / existing_record_count delete_pcent = self.change_counts['Delete'] / existing_record_count
if update_pcent > self.MAX_SAFE_UPDATE_PCENT: if update_pcent > self.update_pcent_threshold:
raise UnsafePlan('Too many updates, {} is over {} percent' raise UnsafePlan('Too many updates, {} is over {} percent'
'({}/{})'.format( '({}/{})'.format(
update_pcent, update_pcent,
self.MAX_SAFE_UPDATE_PCENT * 100, self.MAX_SAFE_UPDATE_PCENT * 100,
self.change_counts['Update'], self.change_counts['Update'],
existing_record_count)) existing_record_count))
if delete_pcent > self.MAX_SAFE_DELETE_PCENT: if delete_pcent > self.delete_pcent_threshold:
raise UnsafePlan('Too many deletes, {} is over {} percent' raise UnsafePlan('Too many deletes, {} is over {} percent'
'({}/{})'.format( '({}/{})'.format(
delete_pcent, delete_pcent,
@@ -79,11 +83,19 @@ class Plan(object):
class BaseProvider(BaseSource): class BaseProvider(BaseSource):
def __init__(self, id, apply_disabled=False): def __init__(self, id, apply_disabled=False,
update_pcent_threshold=Plan.MAX_SAFE_UPDATE_PCENT,
delete_pcent_threshold=Plan.MAX_SAFE_DELETE_PCENT):
super(BaseProvider, self).__init__(id) super(BaseProvider, self).__init__(id)
self.log.debug('__init__: id=%s, apply_disabled=%s', id, self.log.debug('__init__: id=%s, apply_disabled=%s, '
apply_disabled) 'update_pcent_threshold=%d, delete_pcent_threshold=%d',
id,
apply_disabled,
update_pcent_threshold,
delete_pcent_threshold)
self.apply_disabled = apply_disabled self.apply_disabled = apply_disabled
self.update_pcent_threshold = update_pcent_threshold
self.delete_pcent_threshold = delete_pcent_threshold
def _include_change(self, change): def _include_change(self, change):
''' '''
@@ -124,7 +136,9 @@ class BaseProvider(BaseSource):
changes += extra changes += extra
if changes: if changes:
plan = Plan(existing, desired, changes) plan = Plan(existing, desired, changes,
self.update_pcent_threshold,
self.delete_pcent_threshold)
self.log.info('plan: %s', plan) self.log.info('plan: %s', plan)
return plan return plan
self.log.info('plan: No changes') self.log.info('plan: No changes')

View File

@@ -23,6 +23,8 @@ class HelperProvider(BaseProvider):
self.__extra_changes = extra_changes self.__extra_changes = extra_changes
self.apply_disabled = apply_disabled self.apply_disabled = apply_disabled
self.include_change_callback = include_change_callback self.include_change_callback = include_change_callback
self.update_pcent_threshold = Plan.MAX_SAFE_UPDATE_PCENT
self.delete_pcent_threshold = Plan.MAX_SAFE_DELETE_PCENT
def populate(self, zone, target=False, lenient=False): def populate(self, zone, target=False, lenient=False):
pass pass
@@ -288,3 +290,59 @@ class TestBaseProvider(TestCase):
Plan.MAX_SAFE_DELETE_PCENT))] Plan.MAX_SAFE_DELETE_PCENT))]
Plan(zone, zone, changes).raise_if_unsafe() Plan(zone, zone, changes).raise_if_unsafe()
def test_safe_updates_min_existing_override(self):
safe_pcent = .4
# 40% + 1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
record = Record.new(zone, 'a', {
'ttl': 30,
'type': 'A',
'value': '1.2.3.4',
})
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
zone.add_record(Record.new(zone, str(i), {
'ttl': 60,
'type': 'A',
'value': '2.3.4.5'
}))
changes = [Update(record, record)
for i in range(int(Plan.MIN_EXISTING_RECORDS *
safe_pcent) + 1)]
with self.assertRaises(UnsafePlan) as ctx:
Plan(zone, zone, changes,
update_pcent_threshold=safe_pcent).raise_if_unsafe()
self.assertTrue('Too many updates' in ctx.exception.message)
def test_safe_deletes_min_existing_override(self):
safe_pcent = .4
# 40% + 1 fails when more
# than MIN_EXISTING_RECORDS exist
zone = Zone('unit.tests.', [])
record = Record.new(zone, 'a', {
'ttl': 30,
'type': 'A',
'value': '1.2.3.4',
})
for i in range(int(Plan.MIN_EXISTING_RECORDS)):
zone.add_record(Record.new(zone, str(i), {
'ttl': 60,
'type': 'A',
'value': '2.3.4.5'
}))
changes = [Delete(record)
for i in range(int(Plan.MIN_EXISTING_RECORDS *
safe_pcent) + 1)]
with self.assertRaises(UnsafePlan) as ctx:
Plan(zone, zone, changes,
delete_pcent_threshold=safe_pcent).raise_if_unsafe()
self.assertTrue('Too many deletes' in ctx.exception.message)