From 29819e04ec30673b091eeaa89a7129b1da45a4d3 Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2020 06:47:59 +0100 Subject: [PATCH] Add TCP healthcheck support for services registered by consul module (#1144) (#1202) * Add support for consul tcp health check * Fix consul tcp example * Remove trailing spaces * Add changelog fragment * Add format in description * Use regex for tcp * Review fix (cherry picked from commit e13ca30e01e48f5165b97570bf01bdb02ba6e6e5) Co-authored-by: Dmatrix --- .../1144-consul-add-tcp-check-support.yml | 3 ++ plugins/modules/clustering/consul/consul.py | 41 +++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 changelogs/fragments/1144-consul-add-tcp-check-support.yml diff --git a/changelogs/fragments/1144-consul-add-tcp-check-support.yml b/changelogs/fragments/1144-consul-add-tcp-check-support.yml new file mode 100644 index 0000000000..b3a5e54a83 --- /dev/null +++ b/changelogs/fragments/1144-consul-add-tcp-check-support.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - consul - added support for tcp checks (https://github.com/ansible-collections/community.general/issues/1128). diff --git a/plugins/modules/clustering/consul/consul.py b/plugins/modules/clustering/consul/consul.py index 140f0967b5..dd8a5f50c3 100644 --- a/plugins/modules/clustering/consul/consul.py +++ b/plugins/modules/clustering/consul/consul.py @@ -120,6 +120,14 @@ options: Similar to the interval this is a number with a s or m suffix to signify the units of seconds or minutes e.g C(15s) or C(1m). If no suffix is supplied, C(m) will be used by default e.g. C(1) will be C(1m) + tcp: + type: str + description: + - Checks can be registered with a TCP port. This means that consul + will check if the connection attempt to that port is successful (that is, the port is currently accepting connections). + The format is C(host:port), for example C(localhost:80). + I(interval) must also be provided with this option. + version_added: '1.3.0' http: type: str description: @@ -151,6 +159,13 @@ EXAMPLES = ''' script: curl http://localhost interval: 60s +- name: register nginx with a tcp check + community.general.consul: + service_name: nginx + service_port: 80 + interval: 60s + tcp: localhost:80 + - name: Register nginx with an http check community.general.consul: service_name: nginx @@ -217,6 +232,7 @@ try: except ImportError: python_consul_installed = False +import re from ansible.module_utils.basic import AnsibleModule @@ -274,6 +290,7 @@ def add_check(module, check): script=check.script, interval=check.interval, ttl=check.ttl, + tcp=check.tcp, http=check.http, timeout=check.timeout, service_id=check.service_id) @@ -346,11 +363,11 @@ def get_service_by_id_or_name(consul_api, service_id_or_name): def parse_check(module): - if len([p for p in (module.params.get('script'), module.params.get('ttl'), module.params.get('http')) if p]) > 1: + if len([p for p in (module.params.get('script'), module.params.get('ttl'), module.params.get('tcp'), module.params.get('http')) if p]) > 1: module.fail_json( - msg='checks are either script, http or ttl driven, supplying more than one does not make sense') + msg='checks are either script, tcp, http or ttl driven, supplying more than one does not make sense') - if module.params.get('check_id') or module.params.get('script') or module.params.get('ttl') or module.params.get('http'): + if module.params.get('check_id') or module.params.get('script') or module.params.get('ttl') or module.params.get('tcp') or module.params.get('http'): return ConsulCheck( module.params.get('check_id'), @@ -361,6 +378,7 @@ def parse_check(module): module.params.get('interval'), module.params.get('ttl'), module.params.get('notes'), + module.params.get('tcp'), module.params.get('http'), module.params.get('timeout'), module.params.get('service_id'), @@ -446,7 +464,7 @@ class ConsulService(): class ConsulCheck(object): def __init__(self, check_id, name, node=None, host='localhost', - script=None, interval=None, ttl=None, notes=None, http=None, timeout=None, service_id=None): + script=None, interval=None, ttl=None, notes=None, tcp=None, http=None, timeout=None, service_id=None): self.check_id = self.name = name if check_id: self.check_id = check_id @@ -458,6 +476,7 @@ class ConsulCheck(object): self.interval = self.validate_duration('interval', interval) self.ttl = self.validate_duration('ttl', ttl) self.script = script + self.tcp = tcp self.http = http self.timeout = self.validate_duration('timeout', timeout) @@ -475,6 +494,18 @@ class ConsulCheck(object): self.check = consul.Check.http(http, self.interval, self.timeout) + if tcp: + if interval is None: + raise Exception('tcp check must specify interval') + + regex = r"(?P.*)(?::)(?P(?:[0-9]+))$" + match = re.match(regex, tcp) + + if match is None: + raise Exception('tcp check must be in host:port format') + + self.check = consul.Check.tcp(match.group('host').strip('[]'), int(match.group('port')), self.interval) + def validate_duration(self, name, duration): if duration: duration_units = ['ns', 'us', 'ms', 's', 'm', 'h'] @@ -508,6 +539,7 @@ class ConsulCheck(object): self._add(data, 'host') self._add(data, 'interval') self._add(data, 'ttl') + self._add(data, 'tcp') self._add(data, 'http') self._add(data, 'timeout') self._add(data, 'service_id') @@ -547,6 +579,7 @@ def main(): state=dict(default='present', choices=['present', 'absent']), interval=dict(required=False, type='str'), ttl=dict(required=False, type='str'), + tcp=dict(required=False, type='str'), http=dict(required=False, type='str'), timeout=dict(required=False, type='str'), tags=dict(required=False, type='list'),