From 1794f5ccd6ff449e8848d771e7f239d3744d1195 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Runkel?= Date: Mon, 11 Feb 2019 20:02:03 +0100 Subject: [PATCH] Add healthcheck option 'measure_latency' for Route53 provider Route53 allows to monitor latency information on the dashboard and using CloudWatch. While that is a nice to have function, it is not necessary for a DNS failover scenario and increases Route 53 costs. To maintain backward compatibility, the default for this option when ommited is true. --- docs/records.md | 34 +++++++++++++++++++++++--- octodns/provider/route53.py | 23 +++++++++++------ octodns/record/__init__.py | 7 ++++++ tests/test_octodns_provider_route53.py | 15 ++++++++++++ tests/test_octodns_record.py | 3 +++ 5 files changed, 72 insertions(+), 10 deletions(-) diff --git a/docs/records.md b/docs/records.md index a833d4b..1b42055 100644 --- a/docs/records.md +++ b/docs/records.md @@ -72,8 +72,36 @@ So the example is saying: - Europe: gets an "A" record of 111.111.111.4 - Everyone else gets an "A" record of 111.111.111.5 +### Health Checks -Octodns will automatically set up a monitor and check for **https:///_dns** and check for a 200 response. +Octodns will automatically set up monitors for each IP and check for a 200 response for **https:///_dns**. + +These checks can be configured by adding a `healthcheck` configuration to the record: + +```yaml +--- +test: + geo: + AS: + - 1.2.3.4 + EU: + - 2.3.4.5 + octodns: + healthcheck: + host: my-host-name + measure_latency: 0 + path: /dns-health-check + port: 443 + protocol: HTTPS +``` + +| Key | Description | Default | +|--|--|--| +| host | FQDN for host header and SNI | - | +| path | path to check | _dns | +| port | port to check | 443 | +| protocol | HTTP/HTTPS | HTTPS | +| measure_latency | Route53 only: Show latency in AWS console | true | ## Config (`YamlProvider`) @@ -83,7 +111,7 @@ OctoDNS records and `YamlProvider`'s schema is essentially a 1:1 match. Properti Each top-level key in the yaml file is a record name. Two common special cases are the root record `''`, and a wildcard `'*'`. -``` +```yaml --- '': type: A @@ -111,7 +139,7 @@ The above config lays out 4 records, `A`s for `example.com.`, `www.example.com.` In the above example each name had a single record, but there are cases where a name will need to have multiple records associated with it. This can be accomplished by using a list. -``` +```yaml --- '': - type: A diff --git a/octodns/provider/route53.py b/octodns/provider/route53.py index ff83cdc..17a07d0 100644 --- a/octodns/provider/route53.py +++ b/octodns/provider/route53.py @@ -546,11 +546,13 @@ class Route53Provider(BaseProvider): return self._health_checks def _health_check_equivilent(self, host, path, protocol, port, - health_check, first_value=None): + measure_latency, health_check, + first_value=None): config = health_check['HealthCheckConfig'] return host == config['FullyQualifiedDomainName'] and \ path == config['ResourcePath'] and protocol == config['Type'] \ and port == config['Port'] and \ + measure_latency == config['MeasureLatency'] and \ (first_value is None or first_value == config['IPAddress']) def get_health_check_id(self, record, ident, geo, create): @@ -568,6 +570,7 @@ class Route53Provider(BaseProvider): healthcheck_path = record.healthcheck_path healthcheck_protocol = record.healthcheck_protocol healthcheck_port = record.healthcheck_port + healthcheck_measure_latency = record.healthcheck_measure_latency # we're looking for a healthcheck with the current version & our record # type, we'll ignore anything else @@ -580,7 +583,9 @@ class Route53Provider(BaseProvider): if self._health_check_equivilent(healthcheck_host, healthcheck_path, healthcheck_protocol, - healthcheck_port, health_check, + healthcheck_port, + healthcheck_measure_latency, + health_check, first_value=first_value): # this is the health check we're looking for self.log.debug('get_health_check_id: found match id=%s', id) @@ -597,7 +602,7 @@ class Route53Provider(BaseProvider): 'FailureThreshold': 6, 'FullyQualifiedDomainName': healthcheck_host, 'IPAddress': first_value, - 'MeasureLatency': True, + 'MeasureLatency': healthcheck_measure_latency, 'Port': healthcheck_port, 'RequestInterval': 10, 'ResourcePath': healthcheck_path, @@ -612,10 +617,12 @@ class Route53Provider(BaseProvider): # store the new health check so that we'll be able to find it in the # future self._health_checks[id] = health_check - self.log.info('get_health_check_id: created id=%s, host=%s, path=%s, ' - 'protocol=%s, port=%d, first_value=%s', id, - healthcheck_host, healthcheck_path, healthcheck_protocol, - healthcheck_port, first_value) + self.log.info('get_health_check_id: created id=%s, host=%s, ' + 'path=%s, protocol=%s, port=%d, measure_latency=%r, ' + 'first_value=%s', + id, healthcheck_host, healthcheck_path, + healthcheck_protocol, healthcheck_port, + healthcheck_measure_latency, first_value) return id def _gc_health_checks(self, record, new): @@ -728,6 +735,7 @@ class Route53Provider(BaseProvider): healthcheck_path = record.healthcheck_path healthcheck_protocol = record.healthcheck_protocol healthcheck_port = record.healthcheck_port + healthcheck_latency = record.healthcheck_measure_latency fqdn = record.fqdn # loop through all the r53 rrsets @@ -749,6 +757,7 @@ class Route53Provider(BaseProvider): healthcheck_path, healthcheck_protocol, healthcheck_port, + healthcheck_latency, health_check): # it has the right health check continue diff --git a/octodns/record/__init__.py b/octodns/record/__init__.py index ba0ab98..a111415 100644 --- a/octodns/record/__init__.py +++ b/octodns/record/__init__.py @@ -189,6 +189,13 @@ class Record(object): except KeyError: return 443 + @property + def healthcheck_measure_latency(self): + try: + return bool(self._octodns['healthcheck']['measure_latency']) + except KeyError: + return True + def changes(self, other, target): # We're assuming we have the same name and type if we're being compared if self.ttl != other.ttl: diff --git a/tests/test_octodns_provider_route53.py b/tests/test_octodns_provider_route53.py index 75ee991..8cb9863 100644 --- a/tests/test_octodns_provider_route53.py +++ b/tests/test_octodns_provider_route53.py @@ -105,6 +105,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -117,6 +118,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 42, }, { @@ -129,6 +131,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -141,6 +144,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -154,6 +158,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }] @@ -704,6 +709,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -716,6 +722,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }] @@ -738,6 +745,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }] @@ -785,6 +793,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -797,6 +806,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }] @@ -947,6 +957,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -959,6 +970,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }, { @@ -971,6 +983,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }] @@ -1147,6 +1160,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True, }, 'HealthCheckVersion': 2, }], @@ -1250,6 +1264,7 @@ class TestRoute53Provider(TestCase): 'ResourcePath': '/_dns', 'Type': 'HTTPS', 'Port': 443, + 'MeasureLatency': True }, 'HealthCheckVersion': 2, }], diff --git a/tests/test_octodns_record.py b/tests/test_octodns_record.py index 4f05126..411e266 100644 --- a/tests/test_octodns_record.py +++ b/tests/test_octodns_record.py @@ -757,6 +757,7 @@ class TestRecord(TestCase): 'host': 'bleep.bloop', 'protocol': 'HTTP', 'port': 8080, + 'measure_latency': False } } }) @@ -764,6 +765,7 @@ class TestRecord(TestCase): self.assertEquals('bleep.bloop', new.healthcheck_host) self.assertEquals('HTTP', new.healthcheck_protocol) self.assertEquals(8080, new.healthcheck_port) + self.assertEquals(False, new.healthcheck_measure_latency) new = Record.new(self.zone, 'a', { 'ttl': 44, @@ -774,6 +776,7 @@ class TestRecord(TestCase): self.assertEquals('a.unit.tests', new.healthcheck_host) self.assertEquals('HTTPS', new.healthcheck_protocol) self.assertEquals(443, new.healthcheck_port) + self.assertEquals(True, new.healthcheck_measure_latency) def test_inored(self): new = Record.new(self.zone, 'txt', {