Add support for HAProxy L7 checks

This change add several configuration options to enable HTTP checks
to the HAProxy configuration, instead of the default TCP connection
checks (which continue to be the default). It also enables /healthcheck
endpoint for heat-api and heat-cfn-api on openstack releases >= queens.

Closes-Bug: #1880610
Change-Id: I94c9418c82cdddd5a5d9ed400ab47889bfb225b1
This commit is contained in:
Gabriel Cocenza 2023-02-17 11:38:13 -03:00
parent 2a10ff296f
commit 19cf71dc79
4 changed files with 56 additions and 9 deletions

View File

@ -23,6 +23,7 @@ from charmhelpers.core.hookenv import (
from charmhelpers.contrib.hahelpers.cluster import (
determine_apache_port,
determine_api_port,
https,
)
HEAT_PATH = '/var/lib/heat/'
@ -89,12 +90,24 @@ class HeatHAProxyContext(context.OSContextGenerator):
apache_cfn_port = determine_apache_port(haproxy_cfn_port,
singlenode_mode=True)
healthcheck = [{
'option': 'httpchk GET /healthcheck',
'http-check': 'expect status 200',
}]
backend_options = {
'heat_api': healthcheck,
'heat_cfn_api': healthcheck
}
ctxt = {
'service_ports': {'heat_api': [haproxy_port, apache_port],
'heat_cfn_api': [haproxy_cfn_port,
apache_cfn_port]},
'api_listen_port': api_port,
'api_cfn_listen_port': api_cfn_port,
'backend_options': backend_options,
'https': https(),
}
return ctxt

View File

@ -1,7 +1,7 @@
# heat-api pipeline
[pipeline:heat-api]
pipeline = cors request_id faultwrap http_proxy_to_wsgi versionnegotiation osprofiler authurl authtoken context apiv1app
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation osprofiler authurl authtoken context apiv1app
# heat-api pipeline for standalone heat
# ie. uses alternative auth backend that authenticates users against keystone
@ -12,7 +12,7 @@ pipeline = cors request_id faultwrap http_proxy_to_wsgi versionnegotiation ospro
# flavor = standalone
#
[pipeline:heat-api-standalone]
pipeline = cors request_id faultwrap http_proxy_to_wsgi versionnegotiation authurl authpassword context apiv1app
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation authurl authpassword context apiv1app
# heat-api pipeline for custom cloud backends
# i.e. in heat.conf:
@ -20,32 +20,32 @@ pipeline = cors request_id faultwrap http_proxy_to_wsgi versionnegotiation authu
# flavor = custombackend
#
[pipeline:heat-api-custombackend]
pipeline = cors request_id faultwrap versionnegotiation context custombackendauth apiv1app
pipeline = healthcheck cors request_id faultwrap versionnegotiation context custombackendauth apiv1app
# To enable, in heat.conf:
# [paste_deploy]
# flavor = noauth
#
[pipeline:heat-api-noauth]
pipeline = cors request_id faultwrap http_proxy_to_wsgi versionnegotiation noauth context apiv1app
pipeline = healthcheck cors request_id faultwrap http_proxy_to_wsgi versionnegotiation noauth context apiv1app
# heat-api-cfn pipeline
[pipeline:heat-api-cfn]
pipeline = cors http_proxy_to_wsgi cfnversionnegotiation osprofiler ec2authtoken authtoken context apicfnv1app
pipeline = healthcheck cors http_proxy_to_wsgi cfnversionnegotiation osprofiler ec2authtoken authtoken context apicfnv1app
# heat-api-cfn pipeline for standalone heat
# relies exclusively on authenticating with ec2 signed requests
[pipeline:heat-api-cfn-standalone]
pipeline = cors http_proxy_to_wsgi cfnversionnegotiation ec2authtoken context apicfnv1app
pipeline = healthcheck cors http_proxy_to_wsgi cfnversionnegotiation ec2authtoken context apicfnv1app
# heat-api-cloudwatch pipeline
[pipeline:heat-api-cloudwatch]
pipeline = cors versionnegotiation osprofiler ec2authtoken authtoken context apicwapp
pipeline = healthcheck cors versionnegotiation osprofiler ec2authtoken authtoken context apicwapp
# heat-api-cloudwatch pipeline for standalone heat
# relies exclusively on authenticating with ec2 signed requests
[pipeline:heat-api-cloudwatch-standalone]
pipeline = cors versionnegotiation ec2authtoken context apicwapp
pipeline = healthcheck cors versionnegotiation ec2authtoken context apicwapp
[app:apiv1app]
paste.app_factory = heat.common.wsgi:app_factory
@ -115,3 +115,5 @@ paste.filter_factory = oslo_middleware.request_id:RequestId.factory
[filter:osprofiler]
paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
[filter:healthcheck]
paste.filter_factory = oslo_middleware:Healthcheck.factory

View File

@ -25,7 +25,7 @@ setenv = VIRTUAL_ENV={envdir}
commands = stestr run --slowest {posargs}
allowlist_externals =
charmcraft
rename.sh
{toxinidir}/rename.sh
passenv =
HOME
TERM

View File

@ -78,6 +78,38 @@ class TestHeatContext(CharmTestCase):
self.test_config.set('max-stacks-per-tenant', '999')
self.assertEqual(heat_context.QuotaConfigurationContext()(), expected)
@patch('charmhelpers.contrib.hahelpers.cluster.https')
@patch('heat_context.https')
def test_haproxy_context(self, mock_https, mock_ch_https):
for https_mode in [False, True]:
api_cfn_listen_port = 7990
api_listen_port = 7994
if https_mode:
api_cfn_listen_port = 7980
api_listen_port = 7984
mock_https.return_value = https_mode
mock_ch_https.return_value = https_mode
haproxy_context = heat_context.HeatHAProxyContext()
healthcheck = [{
'option': 'httpchk GET /healthcheck',
'http-check': 'expect status 200',
}]
backend_options = {
'heat_api': healthcheck,
'heat_cfn_api': healthcheck
}
expected = {
'service_ports': {
'heat_api': [8004, 7994],
'heat_cfn_api': [8000, 7990]
},
'api_listen_port': api_listen_port,
'api_cfn_listen_port': api_cfn_listen_port,
'backend_options': backend_options,
'https': https_mode,
}
self.assertEqual(expected, haproxy_context())
class HeatPluginContextTest(CharmTestCase):