diff --git a/docs/dynamic_records.md b/docs/dynamic_records.md index fdbb124..f3bdca3 100644 --- a/docs/dynamic_records.md +++ b/docs/dynamic_records.md @@ -130,7 +130,7 @@ Support matrix: * Azure DNS supports only `obey` and `down` * All other dynamic-capable providers only support the default `obey` -#### Route53 Healtch Check Options +#### Route53 Health Check Options | Key | Description | Default | |--|--|--| @@ -220,4 +220,22 @@ Sonar check regions (sonar_regions) possible values: connect_timeout: 2 response_timeout: 10 rapid_recheck: True -``` \ No newline at end of file +``` + +#### [Azure Health Check Options](https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring#configure-endpoint-monitoring) + +| Key | Description | Default | +| ---------------------------- | ------------------------------------------------------------ | ------- | +| interval_in_seconds | This value specifies how often an endpoint is checked for its health from a Traffic Manager probing agent. You can specify two values here: 30 seconds (normal probing) and 10 seconds (fast probing). If no values are provided, the profile sets to a default value of 30 seconds. Visit the [Traffic Manager Pricing](https://azure.microsoft.com/pricing/details/traffic-manager) page to learn more about fast probing pricing. | 30 | +| timeout_in_seconds | This property specifies the amount of time the Traffic Manager probing agent should wait before considering a health probe check to an endpoint a failure. If the Probing Interval is set to 30 seconds, then you can set the Timeout value between 5 and 10 seconds. If no value is specified, it uses a default value of 10 seconds. If the Probing Interval is set to 10 seconds, then you can set the Timeout value between 5 and 9 seconds. If no Timeout value is specified, it uses a default value of 9 seconds. | 10 or 9 | +| tolerated_number_of_failures | This value specifies how many failures a Traffic Manager probing agent tolerates before marking that endpoint as unhealthy. Its value can range between 0 and 9. A value of 0 means a single monitoring failure can cause that endpoint to be marked as unhealthy. If no value is specified, it uses the default value of 3. | 3 | + +``` +--- + octodns: + azuredns: + healthcheck: + interval_in_seconds: 10 + timeout_in_seconds: 7 + tolerated_number_of_failures: 4 +``` diff --git a/octodns/provider/azuredns.py b/octodns/provider/azuredns.py index c78af8f..9eaa8a0 100644 --- a/octodns/provider/azuredns.py +++ b/octodns/provider/azuredns.py @@ -286,11 +286,48 @@ def _pool_traffic_manager_name(pool, record): return f'{prefix}-pool-{pool}' +def _healthcheck_tolerated_number_of_failures(record): + return record._octodns.get('azuredns', {}) \ + .get('healthcheck', {}) \ + .get('tolerated_number_of_failures', None) + + +def _healthcheck_interval_in_seconds(record): + return record._octodns.get('azuredns', {}) \ + .get('healthcheck', {}) \ + .get('interval_in_seconds', None) + + +def _healthcheck_timeout_in_seconds(record): + return record._octodns.get('azuredns', {}) \ + .get('healthcheck', {}) \ + .get('timeout_in_seconds', None) + + def _get_monitor(record): + # We're using None as a sentinal value for optional octoDNS configuration + # values that doesn't end up getting set. For example, if + # `interval_in_seconds` was not entered into the YAML, then + # `_healthcheck_interval_in_seconds(record)` will return None. + # In contrast, when creating a MonitorConfig, optional config is set by + # *not* passing a keyword argument (kwarg). For example, if you want to + # use the default `interval_in_seconds`, you would leave that keyword out + # of your call to `MonitorConfig(...)`. So, when we create a + # MonitorConfig, we need to remove any octoDNS config key that ended up + # with a value of None. + optional_kwargs = { + 'tolerated_number_of_failures': + _healthcheck_tolerated_number_of_failures(record), + 'interval_in_seconds': _healthcheck_interval_in_seconds(record), + 'timeout_in_seconds': _healthcheck_timeout_in_seconds(record), + + } + monitor = MonitorConfig( protocol=record.healthcheck_protocol, port=record.healthcheck_port, path=record.healthcheck_path, + **{k: v for k, v in optional_kwargs.items() if v is not None}, ) host = record.healthcheck_host() if host: @@ -358,6 +395,12 @@ def _profile_is_match(have, desired): if monitor_have.protocol != monitor_desired.protocol or \ monitor_have.port != monitor_desired.port or \ monitor_have.path != monitor_desired.path or \ + monitor_have.tolerated_number_of_failures != \ + monitor_desired.tolerated_number_of_failures or \ + monitor_have.interval_in_seconds != \ + monitor_desired.interval_in_seconds or \ + monitor_have.timeout_in_seconds != \ + monitor_desired.timeout_in_seconds or \ monitor_have.custom_headers != monitor_desired.custom_headers: return false(monitor_have, monitor_desired, have.name) diff --git a/tests/test_octodns_provider_azuredns.py b/tests/test_octodns_provider_azuredns.py index 02dec2f..3318eea 100644 --- a/tests/test_octodns_provider_azuredns.py +++ b/tests/test_octodns_provider_azuredns.py @@ -470,6 +470,7 @@ class Test_ProfileIsMatch(TestCase): monitor_proto = 'HTTPS', monitor_port = 4443, monitor_path = '/_ping', + monitor_optional_kwargs={}, endpoints = 1, endpoint_name = 'name', endpoint_type = 'profile/nestedEndpoints', @@ -487,6 +488,9 @@ class Test_ProfileIsMatch(TestCase): protocol=monitor_proto, port=monitor_port, path=monitor_path, + # see note in azuredns.py's _get_monitor(record) function + **{k: v for k, v + in monitor_optional_kwargs.items() if v is not None}, ), endpoints=[Endpoint( name=endpoint_name, @@ -506,6 +510,12 @@ class Test_ProfileIsMatch(TestCase): self.assertFalse(is_match(profile(), profile(endpoints=2))) self.assertFalse(is_match(profile(), profile(dns_name='two'))) self.assertFalse(is_match(profile(), profile(monitor_proto='HTTP'))) + self.assertFalse(is_match( + profile(), + profile( + monitor_optional_kwargs={'tolerated_number_of_failures': 2} + ), + )) self.assertFalse(is_match(profile(), profile(endpoint_name='a'))) self.assertFalse(is_match(profile(), profile(endpoint_type='b'))) self.assertFalse(