Conditionally use python instead of cURL

The healthcheck_curl has always been a bit bonky with the proxies
management, especially the "no_proxy" environment variable: since there
isn't any real RFC describing the content of this variable, there isn't
any unified handling.

This leads to situation where an Operator puts some CIDR notation inside
this variable, while curl doesn't handle it.

This change adds a new python script. Since it uses python-requests, it
will have a proper support for the CIDR notation[1].

It will be called if and only if either NO_PROXY or no_proxy environment
variables are set and non-empty.

One can also force the script usage by passing HEALTHCHECK_CURL_PY=1,
such as:
podman exec -e "HEALTHCHECK_CURL_PY=1" container /healthchecks/you-healthcheck

The output is 100% iso-compatible, and if someone wants to know what
healthcheck is used, they can check the User-Agent on the target logs.

This change is motivated by, at least, the following existing issues:
https://bugzilla.redhat.com/show_bug.cgi?id=1837458
https://bugzilla.redhat.com/show_bug.cgi?id=1883657

[1] 589c454733/requests/utils.py (L663-L684)

Note: stable/train patch has a different shebang than the original one
due to the CentOS7 support: we don't push any python3 dependencies in
the containers for that OS release.

Depends-On: https://review.rdoproject.org/r/#/c/31813/
Change-Id: If56cd0fa986ef193d036b73e0ab84a88d59147e3
(cherry picked from commit 2185d9a859)
This commit is contained in:
Cédric Jeanneret 2021-01-19 11:41:30 +01:00
parent 71bc42cf7f
commit 74c85faaf0
2 changed files with 54 additions and 1 deletions

View File

@ -9,6 +9,7 @@ else
fi
: ${HEALTHCHECK_CURL_MAX_TIME:=10}
: ${HEALTHCHECK_CURL_USER_AGENT:=curl-healthcheck}
: ${HEALTHCHECK_CURL_PY_USER_AGENT:=pyrequests-healthcheck}
: ${HEALTHCHECK_CURL_WRITE_OUT:='\n%{http_code} %{remote_ip}:%{remote_port} %{time_total} seconds\n'}
: ${HEALTHCHECK_CURL_OUTPUT:='/dev/null'}
@ -30,11 +31,19 @@ healthcheck_curl () {
return 1
fi
export NSS_SDB_USE_CACHE=no
curl -g -k -q -s -S --fail -o "${HEALTHCHECK_CURL_OUTPUT}" \
if [ -n "${HEALTHCHECK_CURL_PY+x}" ] || [ -n "${no_proxy+x}" ] || [ -n "${NO_PROXY+x}" ]; then
${HEALTHCHECK_SCRIPTS:-/usr/share/openstack-tripleo-common/healthcheck}/http-healthcheck.py \
--max-time "${HEALTHCHECK_CURL_MAX_TIME}" \
--user-agent "${HEALTHCHECK_CURL_PY_USER_AGENT}" \
--write-out "${HEALTHCHECK_CURL_WRITE_OUT}" \
"$@" || return 1
else
curl -g -k -q -s -S --fail -o "${HEALTHCHECK_CURL_OUTPUT}" \
--max-time "${HEALTHCHECK_CURL_MAX_TIME}" \
--user-agent "${HEALTHCHECK_CURL_USER_AGENT}" \
--write-out "${HEALTHCHECK_CURL_WRITE_OUT}" \
"$@" || return 1
fi
}
healthcheck_port () {

44
healthcheck/http-healthcheck.py Executable file
View File

@ -0,0 +1,44 @@
#!/usr/bin/python2
import argparse
import os
import requests
default_output = ("\n%(http_code)s %(remote_ip)s:%(remote_port)s "
"%(time_total)s seconds\n")
parser = argparse.ArgumentParser(description='Check remote HTTP')
parser.add_argument('uri', metavar='URI', type=str, nargs=1,
help='Remote URI to check')
parser.add_argument('--max-time', type=int, default=10,
help=('Maximum time in seconds that you allow the'
' whole operation to take.')
)
parser.add_argument('--user-agent', type=str, default='pyrequests-healthcheck',
help=('Specify the User-Agent string to send to the'
' HTTP server.')
)
parser.add_argument('--write-out', type=str, default=default_output,
help=('Display information on stdout after a completed'
' transfer.')
)
args = parser.parse_args()
uri = args.uri[0]
output = args.write_out.replace('%{', '%(').replace('}', ')s') \
.replace('\\n', os.linesep)
headers = {'User-Agent': args.user_agent}
with requests.get(uri, headers=headers, timeout=args.max_time,
allow_redirects=True, stream=True, verify=False) as req:
r_ip, r_port = req.raw._original_response.fp.raw._sock.getpeername()
resp = {'http_code': req.status_code,
'remote_ip': r_ip,
'remote_port': r_port,
'time_total': req.elapsed.total_seconds()
}
try:
print(output % resp)
except KeyError:
print(default_output % resp)
except ValueError:
print(default_output % resp)