Fix AttributeError on TLS-enabled pool provisioning

This patch fixes an hidden AttributeError exception in the HAProxy
driver when adding TLS-enabled pools to listeners.

Task: 40895
Story: 2008150

Change-Id: If165e995a8b61d8a8ed6bc0c4dd036af0c55c6e0
This commit is contained in:
Carlos Goncalves 2020-09-16 12:21:18 +00:00
parent a28bc2a55a
commit a6a4001f57
4 changed files with 24 additions and 15 deletions

View File

@ -203,9 +203,9 @@ class HaproxyAmphoraLoadBalancerDriver(
else: else:
listeners_to_update.append(listener) listeners_to_update.append(listener)
except Exception as e: except Exception as e:
LOG.error('Unable to update listener {0} due to "{1}". ' LOG.exception('Unable to update listener {0} due to '
'Skipping this listener.'.format( '"{1}". Skipping this listener.'.format(
listener.id, str(e))) listener.id, e))
listener_repo = repo.ListenerRepository() listener_repo = repo.ListenerRepository()
listener_repo.update(db_apis.get_session(), listener.id, listener_repo.update(db_apis.get_session(), listener.id,
provisioning_status=consts.ERROR, provisioning_status=consts.ERROR,
@ -531,13 +531,14 @@ class HaproxyAmphoraLoadBalancerDriver(
# Handle the client cert(s) and key # Handle the client cert(s) and key
if pool.tls_certificate_id: if pool.tls_certificate_id:
data = cert_parser.load_certificates_data(self.cert_manager, pool) data = cert_parser.load_certificates_data(self.cert_manager, pool)
pem = cert_parser.build_pem(data) tls_cert = data['tls_cert']
pem = cert_parser.build_pem(tls_cert)
try: try:
pem = pem.encode('utf-8') pem = pem.encode('utf-8')
except AttributeError: except AttributeError:
pass pass
md5 = hashlib.md5(pem).hexdigest() # nosec md5 = hashlib.md5(pem).hexdigest() # nosec
name = '{id}.pem'.format(id=data.id) name = '{id}.pem'.format(id=tls_cert.id)
if amphora and obj_id: if amphora and obj_id:
self._upload_cert(amphora, obj_id, pem=pem, md5=md5, name=name) self._upload_cert(amphora, obj_id, pem=pem, md5=md5, name=name)
pool_cert_dict['client_cert'] = os.path.join( pool_cert_dict['client_cert'] = os.path.join(

View File

@ -25,6 +25,7 @@ from octavia.amphorae.driver_exceptions import exceptions as driver_except
from octavia.amphorae.drivers.haproxy import exceptions as exc from octavia.amphorae.drivers.haproxy import exceptions as exc
from octavia.amphorae.drivers.haproxy import rest_api_driver as driver from octavia.amphorae.drivers.haproxy import rest_api_driver as driver
from octavia.common import constants from octavia.common import constants
from octavia.common import data_models
from octavia.common import utils as octavia_utils from octavia.common import utils as octavia_utils
from octavia.db import models from octavia.db import models
from octavia.network import data_models as network_models from octavia.network import data_models as network_models
@ -399,13 +400,14 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
conf.config(group="haproxy_amphora", base_cert_dir=fake_cert_dir) conf.config(group="haproxy_amphora", base_cert_dir=fake_cert_dir)
sample_listener = sample_configs_split.sample_listener_tuple( sample_listener = sample_configs_split.sample_listener_tuple(
pool_cert=True, pool_ca_cert=True, pool_crl=True) pool_cert=True, pool_ca_cert=True, pool_crl=True)
cert_data_mock = mock.MagicMock() pool_cert = data_models.TLSContainer(
cert_data_mock.id = uuidutils.generate_uuid() id=uuidutils.generate_uuid(), certificate='pool cert')
mock_load_certs.return_value = cert_data_mock pool_data = {'tls_cert': pool_cert, 'sni_certs': []}
mock_load_certs.return_value = pool_data
fake_pem = b'fake pem' fake_pem = b'fake pem'
mock_build_pem.return_value = fake_pem mock_build_pem.return_value = fake_pem
ref_md5 = hashlib.md5(fake_pem).hexdigest() # nosec ref_md5 = hashlib.md5(fake_pem).hexdigest() # nosec
ref_name = '{id}.pem'.format(id=cert_data_mock.id) ref_name = '{id}.pem'.format(id=pool_cert.id)
ref_path = '{cert_dir}/{list_id}/{name}'.format( ref_path = '{cert_dir}/{list_id}/{name}'.format(
cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name) cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name)
ref_ca_name = 'fake_ca.pem' ref_ca_name = 'fake_ca.pem'
@ -432,7 +434,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
sample_listener.default_pool.crl_container_id, sample_listener.default_pool.crl_container_id,
self.amp, sample_listener.load_balancer.id)] self.amp, sample_listener.load_balancer.id)]
mock_build_pem.assert_called_once_with(cert_data_mock) mock_build_pem.assert_called_once_with(pool_cert)
mock_upload_cert.assert_called_once_with( mock_upload_cert.assert_called_once_with(
self.amp, sample_listener.load_balancer.id, pem=fake_pem, self.amp, sample_listener.load_balancer.id, pem=fake_pem,
md5=ref_md5, name=ref_name) md5=ref_md5, name=ref_name)

View File

@ -25,6 +25,7 @@ from octavia.amphorae.driver_exceptions import exceptions as driver_except
from octavia.amphorae.drivers.haproxy import exceptions as exc from octavia.amphorae.drivers.haproxy import exceptions as exc
from octavia.amphorae.drivers.haproxy import rest_api_driver as driver from octavia.amphorae.drivers.haproxy import rest_api_driver as driver
from octavia.common import constants from octavia.common import constants
from octavia.common import data_models
from octavia.common import utils as octavia_utils from octavia.common import utils as octavia_utils
from octavia.db import models from octavia.db import models
from octavia.network import data_models as network_models from octavia.network import data_models as network_models
@ -400,13 +401,14 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
conf.config(group="haproxy_amphora", base_cert_dir=fake_cert_dir) conf.config(group="haproxy_amphora", base_cert_dir=fake_cert_dir)
sample_listener = sample_configs_combined.sample_listener_tuple( sample_listener = sample_configs_combined.sample_listener_tuple(
pool_cert=True, pool_ca_cert=True, pool_crl=True) pool_cert=True, pool_ca_cert=True, pool_crl=True)
cert_data_mock = mock.MagicMock() pool_cert = data_models.TLSContainer(
cert_data_mock.id = uuidutils.generate_uuid() id=uuidutils.generate_uuid(), certificate='pool cert')
mock_load_certs.return_value = cert_data_mock pool_data = {'tls_cert': pool_cert, 'sni_certs': []}
mock_load_certs.return_value = pool_data
fake_pem = b'fake pem' fake_pem = b'fake pem'
mock_build_pem.return_value = fake_pem mock_build_pem.return_value = fake_pem
ref_md5 = hashlib.md5(fake_pem).hexdigest() # nosec ref_md5 = hashlib.md5(fake_pem).hexdigest() # nosec
ref_name = '{id}.pem'.format(id=cert_data_mock.id) ref_name = '{id}.pem'.format(id=pool_cert.id)
ref_path = '{cert_dir}/{list_id}/{name}'.format( ref_path = '{cert_dir}/{list_id}/{name}'.format(
cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name) cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name)
ref_ca_name = 'fake_ca.pem' ref_ca_name = 'fake_ca.pem'
@ -433,7 +435,7 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
sample_listener.default_pool.crl_container_id, sample_listener.default_pool.crl_container_id,
self.amp, sample_listener.load_balancer.id)] self.amp, sample_listener.load_balancer.id)]
mock_build_pem.assert_called_once_with(cert_data_mock) mock_build_pem.assert_called_once_with(pool_cert)
mock_upload_cert.assert_called_once_with( mock_upload_cert.assert_called_once_with(
self.amp, sample_listener.load_balancer.id, pem=fake_pem, self.amp, sample_listener.load_balancer.id, pem=fake_pem,
md5=ref_md5, name=ref_name) md5=ref_md5, name=ref_name)

View File

@ -0,0 +1,4 @@
---
fixes:
- |
Fixed an issue where TLS-enabled pools would fail to provision.