diff --git a/designate/__init__.py b/designate/__init__.py index 6295de4a7..fe01ccb7f 100644 --- a/designate/__init__.py +++ b/designate/__init__.py @@ -54,7 +54,9 @@ cfg.CONF.register_opts([ cfg.IntOpt('default-ttl', default=3600), # Default SOA Values - cfg.IntOpt('default-soa-refresh', default=3600), + cfg.IntOpt('default-soa-refresh-min', default=3500, + deprecated_name='default-soa-refresh'), + cfg.IntOpt('default-soa-refresh-max', default=3600), cfg.IntOpt('default-soa-retry', default=600), cfg.IntOpt('default-soa-expire', default=86400), cfg.IntOpt('default-soa-minimum', default=3600), diff --git a/designate/central/service.py b/designate/central/service.py index e03226140..c639954d9 100644 --- a/designate/central/service.py +++ b/designate/central/service.py @@ -843,6 +843,20 @@ class Service(service.RPCService, service.Service): return self.storage.count_tenants(context) # Zone Methods + + def _generate_soa_refresh_interval(self): + """Generate a random refresh interval to stagger AXFRs across multiple + zones and resolvers + maximum val: default_soa_refresh_min + minimum val: default_soa_refresh_max + """ + assert cfg.CONF.default_soa_refresh_min is not None + assert cfg.CONF.default_soa_refresh_max is not None + dispersion = (cfg.CONF.default_soa_refresh_max - + cfg.CONF.default_soa_refresh_min) * random.random() + refresh_time = cfg.CONF.default_soa_refresh_min + dispersion + return int(refresh_time) + @notification('dns.domain.create') @notification('dns.zone.create') @synchronized_zone(new_zone=True) @@ -914,6 +928,9 @@ class Service(service.RPCService, service.Service): if zone.type == 'SECONDARY' and zone.serial is None: zone.serial = 1 + # randomize the zone refresh time + zone.refresh = self._generate_soa_refresh_interval() + zone = self._create_zone_in_storage(context, zone) self.pool_manager_api.create_zone(context, zone) diff --git a/designate/storage/impl_sqlalchemy/tables.py b/designate/storage/impl_sqlalchemy/tables.py index c2cc258f8..639b05d2a 100644 --- a/designate/storage/impl_sqlalchemy/tables.py +++ b/designate/storage/impl_sqlalchemy/tables.py @@ -44,6 +44,10 @@ ZONE_TASK_TYPES = ['IMPORT', 'EXPORT'] metadata = MetaData() +# TODO(Federico) some default column values are not needed because we +# explicitely set the value on record insertion. Having default values could +# hide bugs. + def default_shard(context, id_col): return int(context.current_parameters[id_col][0:3], 16) @@ -96,7 +100,8 @@ zones = Table('zones', metadata, Column('transferred_at', DateTime, default=None), Column('ttl', Integer, default=CONF.default_ttl, nullable=False), Column('serial', Integer, default=timeutils.utcnow_ts, nullable=False), - Column('refresh', Integer, default=CONF.default_soa_refresh, + # The refresh interval is randomized by _generate_soa_refresh_interval + Column('refresh', Integer, default=CONF.default_soa_refresh_min, nullable=False), Column('retry', Integer, default=CONF.default_soa_retry, nullable=False), Column('expire', Integer, default=CONF.default_soa_expire, nullable=False), diff --git a/designate/tests/test_central/test_service.py b/designate/tests/test_central/test_service.py index 52fc3b74e..345d0a0af 100644 --- a/designate/tests/test_central/test_service.py +++ b/designate/tests/test_central/test_service.py @@ -517,6 +517,11 @@ class CentralServiceTest(CentralTestCase): with testtools.ExpectedException(exceptions.OverQuota): self.create_zone() + def test_create_zone_with_refresh_time_dispersion(self): + random.seed(42) + zone = self.create_zone() + self.assertEqual(3563, zone['refresh']) + def test_create_subzone(self): # Create the Parent Zone using fixture 0 parent_zone = self.create_zone(fixture=0) diff --git a/doc/source/gmr.rst b/doc/source/gmr.rst index d58407a84..7549f517b 100644 --- a/doc/source/gmr.rst +++ b/doc/source/gmr.rst @@ -4,7 +4,7 @@ Guru Meditation Reports ========================= -A Guru Meditation Reports(GMR) is generated by the Designate services when +A Guru Meditation Report (GMR) is generated by the Designate services when service processes receiving SIGUSR2 signal. The report is a general-purpose debug report for developers and system admins which contains the current state of a running Designate service process. @@ -309,7 +309,8 @@ GMR Example debug = True default-soa-expire = 86400 default-soa-minimum = 3600 - default-soa-refresh = 3600 + default-soa-refresh-min = 3500 + default-soa-refresh-max = 3600 default-soa-retry = 600 default-ttl = 3600 default_log_levels = diff --git a/releasenotes/notes/soa_refresh_interval_randomization-fcc1d0d63124699b.yaml b/releasenotes/notes/soa_refresh_interval_randomization-fcc1d0d63124699b.yaml new file mode 100644 index 000000000..5a4dd7d3c --- /dev/null +++ b/releasenotes/notes/soa_refresh_interval_randomization-fcc1d0d63124699b.yaml @@ -0,0 +1,8 @@ +--- +features: + - Randomize SOA refresh interval to stagger AXFRs across multiple zones and + resolvers. + Introduce the new configuration parameters default-soa-refresh-min and + default-soa-refresh-max +deprecations: + - default-soa-refresh configuration option