mirror of
https://github.com/github/octodns.git
synced 2024-05-11 05:55:00 +00:00
Merge pull request #321 from jrunkel/add-route53-measurelatency-option
Add healthcheck option 'measure_latency' for Route53 provider
This commit is contained in:
@@ -72,8 +72,54 @@ So the example is saying:
|
|||||||
- Europe: gets an "A" record of 111.111.111.4
|
- Europe: gets an "A" record of 111.111.111.4
|
||||||
- Everyone else gets an "A" record of 111.111.111.5
|
- Everyone else gets an "A" record of 111.111.111.5
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
|
||||||
|
Octodns will automatically set up monitors for each IP and check for a 200 response for **https://<ip_address>/_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
|
||||||
|
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 |
|
||||||
|
|
||||||
|
#### Route53 Healtch Check Options
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
|--|--|--|
|
||||||
|
| measure_latency | Show latency in AWS console | true |
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
---
|
||||||
|
octodns:
|
||||||
|
healthcheck:
|
||||||
|
host: my-host-name
|
||||||
|
path: /dns-health-check
|
||||||
|
port: 443
|
||||||
|
protocol: HTTPS
|
||||||
|
route53:
|
||||||
|
healthcheck:
|
||||||
|
measure_latency: false
|
||||||
|
```
|
||||||
|
|
||||||
Octodns will automatically set up a monitor and check for **https://<ip_address>/_dns** and check for a 200 response.
|
|
||||||
|
|
||||||
## Config (`YamlProvider`)
|
## Config (`YamlProvider`)
|
||||||
|
|
||||||
@@ -83,7 +129,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 `'*'`.
|
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
|
type: A
|
||||||
@@ -111,7 +157,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.
|
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
|
- type: A
|
||||||
|
|||||||
@@ -545,12 +545,19 @@ class Route53Provider(BaseProvider):
|
|||||||
# We've got a cached version use it
|
# We've got a cached version use it
|
||||||
return self._health_checks
|
return self._health_checks
|
||||||
|
|
||||||
|
def _healthcheck_measure_latency(self, record):
|
||||||
|
return record._octodns.get('route53', {}) \
|
||||||
|
.get('healthcheck', {}) \
|
||||||
|
.get('measure_latency', True)
|
||||||
|
|
||||||
def _health_check_equivilent(self, host, path, protocol, port,
|
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']
|
config = health_check['HealthCheckConfig']
|
||||||
return host == config['FullyQualifiedDomainName'] and \
|
return host == config['FullyQualifiedDomainName'] and \
|
||||||
path == config['ResourcePath'] and protocol == config['Type'] \
|
path == config['ResourcePath'] and protocol == config['Type'] \
|
||||||
and port == config['Port'] and \
|
and port == config['Port'] and \
|
||||||
|
measure_latency == config['MeasureLatency'] and \
|
||||||
(first_value is None or first_value == config['IPAddress'])
|
(first_value is None or first_value == config['IPAddress'])
|
||||||
|
|
||||||
def get_health_check_id(self, record, ident, geo, create):
|
def get_health_check_id(self, record, ident, geo, create):
|
||||||
@@ -568,6 +575,7 @@ class Route53Provider(BaseProvider):
|
|||||||
healthcheck_path = record.healthcheck_path
|
healthcheck_path = record.healthcheck_path
|
||||||
healthcheck_protocol = record.healthcheck_protocol
|
healthcheck_protocol = record.healthcheck_protocol
|
||||||
healthcheck_port = record.healthcheck_port
|
healthcheck_port = record.healthcheck_port
|
||||||
|
healthcheck_latency = self._healthcheck_measure_latency(record)
|
||||||
|
|
||||||
# we're looking for a healthcheck with the current version & our record
|
# we're looking for a healthcheck with the current version & our record
|
||||||
# type, we'll ignore anything else
|
# type, we'll ignore anything else
|
||||||
@@ -580,7 +588,9 @@ class Route53Provider(BaseProvider):
|
|||||||
if self._health_check_equivilent(healthcheck_host,
|
if self._health_check_equivilent(healthcheck_host,
|
||||||
healthcheck_path,
|
healthcheck_path,
|
||||||
healthcheck_protocol,
|
healthcheck_protocol,
|
||||||
healthcheck_port, health_check,
|
healthcheck_port,
|
||||||
|
healthcheck_latency,
|
||||||
|
health_check,
|
||||||
first_value=first_value):
|
first_value=first_value):
|
||||||
# this is the health check we're looking for
|
# this is the health check we're looking for
|
||||||
self.log.debug('get_health_check_id: found match id=%s', id)
|
self.log.debug('get_health_check_id: found match id=%s', id)
|
||||||
@@ -597,7 +607,7 @@ class Route53Provider(BaseProvider):
|
|||||||
'FailureThreshold': 6,
|
'FailureThreshold': 6,
|
||||||
'FullyQualifiedDomainName': healthcheck_host,
|
'FullyQualifiedDomainName': healthcheck_host,
|
||||||
'IPAddress': first_value,
|
'IPAddress': first_value,
|
||||||
'MeasureLatency': True,
|
'MeasureLatency': healthcheck_latency,
|
||||||
'Port': healthcheck_port,
|
'Port': healthcheck_port,
|
||||||
'RequestInterval': 10,
|
'RequestInterval': 10,
|
||||||
'ResourcePath': healthcheck_path,
|
'ResourcePath': healthcheck_path,
|
||||||
@@ -612,10 +622,12 @@ class Route53Provider(BaseProvider):
|
|||||||
# store the new health check so that we'll be able to find it in the
|
# store the new health check so that we'll be able to find it in the
|
||||||
# future
|
# future
|
||||||
self._health_checks[id] = health_check
|
self._health_checks[id] = health_check
|
||||||
self.log.info('get_health_check_id: created id=%s, host=%s, path=%s, '
|
self.log.info('get_health_check_id: created id=%s, host=%s, '
|
||||||
'protocol=%s, port=%d, first_value=%s', id,
|
'path=%s, protocol=%s, port=%d, measure_latency=%r, '
|
||||||
healthcheck_host, healthcheck_path, healthcheck_protocol,
|
'first_value=%s',
|
||||||
healthcheck_port, first_value)
|
id, healthcheck_host, healthcheck_path,
|
||||||
|
healthcheck_protocol, healthcheck_port,
|
||||||
|
healthcheck_latency, first_value)
|
||||||
return id
|
return id
|
||||||
|
|
||||||
def _gc_health_checks(self, record, new):
|
def _gc_health_checks(self, record, new):
|
||||||
@@ -728,6 +740,7 @@ class Route53Provider(BaseProvider):
|
|||||||
healthcheck_path = record.healthcheck_path
|
healthcheck_path = record.healthcheck_path
|
||||||
healthcheck_protocol = record.healthcheck_protocol
|
healthcheck_protocol = record.healthcheck_protocol
|
||||||
healthcheck_port = record.healthcheck_port
|
healthcheck_port = record.healthcheck_port
|
||||||
|
healthcheck_latency = self._healthcheck_measure_latency(record)
|
||||||
fqdn = record.fqdn
|
fqdn = record.fqdn
|
||||||
|
|
||||||
# loop through all the r53 rrsets
|
# loop through all the r53 rrsets
|
||||||
@@ -749,6 +762,7 @@ class Route53Provider(BaseProvider):
|
|||||||
healthcheck_path,
|
healthcheck_path,
|
||||||
healthcheck_protocol,
|
healthcheck_protocol,
|
||||||
healthcheck_port,
|
healthcheck_port,
|
||||||
|
healthcheck_latency,
|
||||||
health_check):
|
health_check):
|
||||||
# it has the right health check
|
# it has the right health check
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -117,6 +118,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 42,
|
'HealthCheckVersion': 42,
|
||||||
}, {
|
}, {
|
||||||
@@ -129,6 +131,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -141,6 +144,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -154,6 +158,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}]
|
}]
|
||||||
@@ -704,6 +709,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -716,6 +722,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}]
|
}]
|
||||||
@@ -738,6 +745,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}]
|
}]
|
||||||
@@ -785,6 +793,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -797,6 +806,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}]
|
}]
|
||||||
@@ -858,6 +868,107 @@ class TestRoute53Provider(TestCase):
|
|||||||
self.assertEquals('42', id)
|
self.assertEquals('42', id)
|
||||||
stubber.assert_no_pending_responses()
|
stubber.assert_no_pending_responses()
|
||||||
|
|
||||||
|
def test_health_check_measure_latency(self):
|
||||||
|
provider, stubber = self._get_stubbed_provider()
|
||||||
|
record_true = Record.new(self.expected, 'a', {
|
||||||
|
'ttl': 61,
|
||||||
|
'type': 'A',
|
||||||
|
'value': '1.2.3.4',
|
||||||
|
'octodns': {
|
||||||
|
'healthcheck': {
|
||||||
|
},
|
||||||
|
'route53': {
|
||||||
|
'healthcheck': {
|
||||||
|
'measure_latency': True
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
measure_latency = provider._healthcheck_measure_latency(record_true)
|
||||||
|
self.assertTrue(measure_latency)
|
||||||
|
|
||||||
|
record_default = Record.new(self.expected, 'a', {
|
||||||
|
'ttl': 61,
|
||||||
|
'type': 'A',
|
||||||
|
'value': '1.2.3.4',
|
||||||
|
})
|
||||||
|
measure_latency = provider._healthcheck_measure_latency(record_default)
|
||||||
|
self.assertTrue(measure_latency)
|
||||||
|
|
||||||
|
record_false = Record.new(self.expected, 'a', {
|
||||||
|
'ttl': 61,
|
||||||
|
'type': 'A',
|
||||||
|
'value': '1.2.3.4',
|
||||||
|
'octodns': {
|
||||||
|
'healthcheck': {
|
||||||
|
},
|
||||||
|
'route53': {
|
||||||
|
'healthcheck': {
|
||||||
|
'measure_latency': False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
measure_latency = provider._healthcheck_measure_latency(record_false)
|
||||||
|
self.assertFalse(measure_latency)
|
||||||
|
|
||||||
|
def test_create_health_checks_measure_latency(self):
|
||||||
|
provider, stubber = self._get_stubbed_provider()
|
||||||
|
|
||||||
|
health_check_config = {
|
||||||
|
'EnableSNI': True,
|
||||||
|
'FailureThreshold': 6,
|
||||||
|
'FullyQualifiedDomainName': 'a.unit.tests',
|
||||||
|
'IPAddress': '1.2.3.4',
|
||||||
|
'MeasureLatency': False,
|
||||||
|
'Port': 443,
|
||||||
|
'RequestInterval': 10,
|
||||||
|
'ResourcePath': '/_dns',
|
||||||
|
'Type': 'HTTPS'
|
||||||
|
}
|
||||||
|
|
||||||
|
stubber.add_response('list_health_checks', {
|
||||||
|
'HealthChecks': [],
|
||||||
|
'IsTruncated': False,
|
||||||
|
'MaxItems': '100',
|
||||||
|
'Marker': '',
|
||||||
|
})
|
||||||
|
|
||||||
|
stubber.add_response('create_health_check', {
|
||||||
|
'HealthCheck': {
|
||||||
|
'Id': '42',
|
||||||
|
'CallerReference': self.caller_ref,
|
||||||
|
'HealthCheckConfig': health_check_config,
|
||||||
|
'HealthCheckVersion': 1,
|
||||||
|
},
|
||||||
|
'Location': 'http://url',
|
||||||
|
}, {
|
||||||
|
'CallerReference': ANY,
|
||||||
|
'HealthCheckConfig': health_check_config,
|
||||||
|
})
|
||||||
|
|
||||||
|
record = Record.new(self.expected, 'a', {
|
||||||
|
'ttl': 61,
|
||||||
|
'type': 'A',
|
||||||
|
'value': '2.2.3.4',
|
||||||
|
'geo': {
|
||||||
|
'AF': ['1.2.3.4'],
|
||||||
|
},
|
||||||
|
'octodns': {
|
||||||
|
'healthcheck': {
|
||||||
|
},
|
||||||
|
'route53': {
|
||||||
|
'healthcheck': {
|
||||||
|
'measure_latency': False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
id = provider.get_health_check_id(record, 'AF', record.geo['AF'], True)
|
||||||
|
ml = provider.health_checks[id]['HealthCheckConfig']['MeasureLatency']
|
||||||
|
self.assertEqual(False, ml)
|
||||||
|
|
||||||
def test_health_check_gc(self):
|
def test_health_check_gc(self):
|
||||||
provider, stubber = self._get_stubbed_provider()
|
provider, stubber = self._get_stubbed_provider()
|
||||||
|
|
||||||
@@ -947,6 +1058,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -959,6 +1071,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}, {
|
}, {
|
||||||
@@ -971,6 +1084,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}]
|
}]
|
||||||
@@ -1147,6 +1261,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True,
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}],
|
}],
|
||||||
@@ -1250,6 +1365,7 @@ class TestRoute53Provider(TestCase):
|
|||||||
'ResourcePath': '/_dns',
|
'ResourcePath': '/_dns',
|
||||||
'Type': 'HTTPS',
|
'Type': 'HTTPS',
|
||||||
'Port': 443,
|
'Port': 443,
|
||||||
|
'MeasureLatency': True
|
||||||
},
|
},
|
||||||
'HealthCheckVersion': 2,
|
'HealthCheckVersion': 2,
|
||||||
}],
|
}],
|
||||||
|
|||||||
Reference in New Issue
Block a user