Fix backend certificate file paths

In amphora-agent API version 1.0, backend certificate files are uploaded
to /var/lib/octavia/certs/<lb_id>/. However, the "server" line in the
rendered HAProxy configuration sets the certificate paths to
/var/lib/octavia/certs/<listener_id>/ (amphora-agent version 0.5).

This renders an invalid HAProxy configuration file and as result HAProxy
fails to reload with the new configuration, and members marked in ERROR
provisioning status.

Task: 40903
Story: 2008157

Change-Id: I7e2b12f19ee7b172464e809df6342ade1e87fb2e
This commit is contained in:
Carlos Goncalves 2020-09-17 09:35:50 +00:00
parent a6a4001f57
commit 89d5e9fcf6
4 changed files with 31 additions and 26 deletions

View File

@ -506,8 +506,7 @@ class HaproxyAmphoraLoadBalancerDriver(
amphora, obj_id, pem=secret, md5=md5, name=name) amphora, obj_id, pem=secret, md5=md5, name=name)
return name return name
def _process_listener_pool_certs(self, listener, amphora=None, def _process_listener_pool_certs(self, listener, amphora, obj_id):
obj_id=None):
# {'POOL-ID': { # {'POOL-ID': {
# 'client_cert': client_full_filename, # 'client_cert': client_full_filename,
# 'ca_cert': ca_cert_full_filename, # 'ca_cert': ca_cert_full_filename,
@ -525,7 +524,7 @@ class HaproxyAmphoraLoadBalancerDriver(
amphora, obj_id)) amphora, obj_id))
return pool_certs_dict return pool_certs_dict
def _process_pool_certs(self, listener, pool, amphora=None, obj_id=None): def _process_pool_certs(self, listener, pool, amphora, obj_id):
pool_cert_dict = dict() pool_cert_dict = dict()
# Handle the client cert(s) and key # Handle the client cert(s) and key
@ -542,17 +541,17 @@ class HaproxyAmphoraLoadBalancerDriver(
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(
CONF.haproxy_amphora.base_cert_dir, listener.id, name) CONF.haproxy_amphora.base_cert_dir, obj_id, name)
if pool.ca_tls_certificate_id: if pool.ca_tls_certificate_id:
name = self._process_secret(listener, pool.ca_tls_certificate_id, name = self._process_secret(listener, pool.ca_tls_certificate_id,
amphora, obj_id) amphora, obj_id)
pool_cert_dict['ca_cert'] = os.path.join( pool_cert_dict['ca_cert'] = os.path.join(
CONF.haproxy_amphora.base_cert_dir, listener.id, name) CONF.haproxy_amphora.base_cert_dir, obj_id, name)
if pool.crl_container_id: if pool.crl_container_id:
name = self._process_secret(listener, pool.crl_container_id, name = self._process_secret(listener, pool.crl_container_id,
amphora, obj_id) amphora, obj_id)
pool_cert_dict['crl'] = os.path.join( pool_cert_dict['crl'] = os.path.join(
CONF.haproxy_amphora.base_cert_dir, listener.id, name) CONF.haproxy_amphora.base_cert_dir, obj_id, name)
return pool_cert_dict return pool_cert_dict

View File

@ -287,14 +287,14 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [ self.driver.clients[API_VERSION].get_cert_md5sum.side_effect = [
exc.NotFound, 'Fake_MD5', 'aaaaa', 'aaaaaaaa'] exc.NotFound, 'Fake_MD5', 'aaaaa', 'aaaaaaaa']
self.driver._process_tls_certificates( self.driver._process_tls_certificates(
sample_listener, self.amp, sample_listener.load_balancer.id) sample_listener, self.amp, sample_listener.id)
gcm_calls = [ gcm_calls = [
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
self.sl.default_tls_container.id + '.pem', self.sl.default_tls_container.id + '.pem',
ignore=(404,)), ignore=(404,)),
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
sconts[0].id + '.pem', ignore=(404,)), sconts[0].id + '.pem', ignore=(404,)),
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
sconts[1].id + '.pem', ignore=(404,)) sconts[1].id + '.pem', ignore=(404,))
] ]
self.driver.clients[API_VERSION].get_cert_md5sum.assert_has_calls( self.driver.clients[API_VERSION].get_cert_md5sum.assert_has_calls(
@ -309,11 +309,11 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
sample_certs.X509_CERT_KEY_3, sample_certs.X509_CERT_KEY_3,
sample_certs.X509_IMDS]) + b'\n' sample_certs.X509_IMDS]) + b'\n'
ucp_calls = [ ucp_calls = [
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
self.sl.default_tls_container.id + '.pem', fp1), self.sl.default_tls_container.id + '.pem', fp1),
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
sconts[0].id + '.pem', fp2), sconts[0].id + '.pem', fp2),
mock.call(self.amp, self.lb.id, mock.call(self.amp, sample_listener.id,
sconts[1].id + '.pem', fp3) sconts[1].id + '.pem', fp3)
] ]
self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls( self.driver.clients[API_VERSION].upload_cert_pem.assert_has_calls(
@ -374,13 +374,13 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
'sample_pool_id_2': ref_pool_cert_2} 'sample_pool_id_2': ref_pool_cert_2}
result = self.driver._process_listener_pool_certs( result = self.driver._process_listener_pool_certs(
sample_listener, self.amp, sample_listener.load_balancer.id) sample_listener, self.amp, sample_listener.id)
pool_certs_calls = [ pool_certs_calls = [
mock.call(sample_listener, sample_listener.default_pool, mock.call(sample_listener, sample_listener.default_pool,
self.amp, sample_listener.load_balancer.id), self.amp, sample_listener.id),
mock.call(sample_listener, sample_listener.pools[1], mock.call(sample_listener, sample_listener.pools[1],
self.amp, sample_listener.load_balancer.id) self.amp, sample_listener.id)
] ]
mock_pool_cert.assert_has_calls(pool_certs_calls, any_order=True) mock_pool_cert.assert_has_calls(pool_certs_calls, any_order=True)
@ -424,19 +424,19 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
result = self.driver._process_pool_certs( result = self.driver._process_pool_certs(
sample_listener, sample_listener.default_pool, self.amp, sample_listener, sample_listener.default_pool, self.amp,
sample_listener.load_balancer.id) sample_listener.id)
secret_calls = [ secret_calls = [
mock.call(sample_listener, mock.call(sample_listener,
sample_listener.default_pool.ca_tls_certificate_id, sample_listener.default_pool.ca_tls_certificate_id,
self.amp, sample_listener.load_balancer.id), self.amp, sample_listener.id),
mock.call(sample_listener, mock.call(sample_listener,
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.id)]
mock_build_pem.assert_called_once_with(pool_cert) 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.id, pem=fake_pem,
md5=ref_md5, name=ref_name) md5=ref_md5, name=ref_name)
mock_secret.assert_has_calls(secret_calls) mock_secret.assert_has_calls(secret_calls)
self.assertEqual(ref_result, result) self.assertEqual(ref_result, result)

View File

@ -409,15 +409,16 @@ class TestHaproxyAmphoraLoadBalancerDriverTest(base.TestCase):
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=pool_cert.id) ref_name = '{id}.pem'.format(id=pool_cert.id)
ref_path = '{cert_dir}/{list_id}/{name}'.format( ref_path = '{cert_dir}/{lb_id}/{name}'.format(
cert_dir=fake_cert_dir, list_id=sample_listener.id, name=ref_name) cert_dir=fake_cert_dir, lb_id=sample_listener.load_balancer.id,
name=ref_name)
ref_ca_name = 'fake_ca.pem' ref_ca_name = 'fake_ca.pem'
ref_ca_path = '{cert_dir}/{list_id}/{name}'.format( ref_ca_path = '{cert_dir}/{lb_id}/{name}'.format(
cert_dir=fake_cert_dir, list_id=sample_listener.id, cert_dir=fake_cert_dir, lb_id=sample_listener.load_balancer.id,
name=ref_ca_name) name=ref_ca_name)
ref_crl_name = 'fake_crl.pem' ref_crl_name = 'fake_crl.pem'
ref_crl_path = '{cert_dir}/{list_id}/{name}'.format( ref_crl_path = '{cert_dir}/{lb_id}/{name}'.format(
cert_dir=fake_cert_dir, list_id=sample_listener.id, cert_dir=fake_cert_dir, lb_id=sample_listener.load_balancer.id,
name=ref_crl_name) name=ref_crl_name)
ref_result = {'client_cert': ref_path, 'ca_cert': ref_ca_path, ref_result = {'client_cert': ref_path, 'ca_cert': ref_ca_path,
'crl': ref_crl_path} 'crl': ref_crl_path}

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fixed an issue where members added to TLS-enabled pools would go to ERROR
provisioning status.