Merge "Handle Octavia certificates properly"

This commit is contained in:
Zuul 2020-05-09 17:02:52 +00:00 committed by Gerrit Code Review
commit e5640f074c
6 changed files with 53 additions and 49 deletions

View File

@ -58,3 +58,8 @@ def session_persistence_type_changed(pool, old_pool):
oldsp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP)): oldsp['type'] == lb_const.LB_SESSION_PERSISTENCE_SOURCE_IP)):
return True return True
return False return False
def get_listener_cert_ref(listener):
return listener.get('default_tls_container_id',
listener.get('default_tls_container_ref'))

View File

@ -52,13 +52,13 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
nsxpolicy = self.core_plugin.nsxpolicy nsxpolicy = self.core_plugin.nsxpolicy
cert_client = nsxpolicy.certificate cert_client = nsxpolicy.certificate
ssl_client = nsxpolicy.load_balancer.client_ssl_profile ssl_client = nsxpolicy.load_balancer.client_ssl_profile
passphrase = certificate.get_private_key_passphrase() passphrase = certificate.get('passphrase')
if not passphrase: if not passphrase:
passphrase = core_resources.IGNORE passphrase = core_resources.IGNORE
cert_client.create_or_overwrite( cert_client.create_or_overwrite(
cert_href, certificate_id=listener_id, cert_href, certificate_id=listener_id,
pem_encoded=certificate.get_certificate(), pem_encoded=certificate.get('certificate'),
private_key=certificate.get_private_key(), private_key=certificate.get('private_key'),
passphrase=passphrase, passphrase=passphrase,
tags=tags) tags=tags)
@ -103,7 +103,7 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
kwargs['lb_persistence_profile_id'] = '' kwargs['lb_persistence_profile_id'] = ''
if certificate: if certificate:
ssl_profile_binding = self._upload_certificate( ssl_profile_binding = self._upload_certificate(
listener['id'], listener['default_tls_container_id'], tags, listener['id'], certificate['ref'], tags,
certificate=certificate) certificate=certificate)
if (listener['protocol'] == if (listener['protocol'] ==
lb_const.LB_PROTOCOL_TERMINATED_HTTPS and lb_const.LB_PROTOCOL_TERMINATED_HTTPS and
@ -304,7 +304,7 @@ class EdgeListenerManagerFromDict(base_mgr.NsxpLoadbalancerBaseManager):
"NSX: %s", app_profile_id, e) "NSX: %s", app_profile_id, e)
# Delete imported NSX cert if there is any # Delete imported NSX cert if there is any
if listener.get('default_tls_container_id'): if lb_common.get_listener_cert_ref(listener):
cert_client = self.core_plugin.nsxpolicy.certificate cert_client = self.core_plugin.nsxpolicy.certificate
try: try:
cert_client.delete(listener['id']) cert_client.delete(listener['id'])

View File

@ -25,8 +25,9 @@ from vmware_nsx.common import locking
from vmware_nsx.db import nsxv_db from vmware_nsx.db import nsxv_db
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as vcns_exc from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as vcns_exc
from vmware_nsx.services.lbaas import base_mgr from vmware_nsx.services.lbaas import base_mgr
from vmware_nsx.services.lbaas import lb_common
from vmware_nsx.services.lbaas import lb_const from vmware_nsx.services.lbaas import lb_const
from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_common from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_v_common
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@ -132,9 +133,9 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
return cert_binding['edge_cert_id'] return cert_binding['edge_cert_id']
request = { request = {
'pemEncoding': certificate.get_certificate(), 'pemEncoding': certificate.get('certificate'),
'privateKey': certificate.get_private_key()} 'privateKey': certificate.get('private_key')}
passphrase = certificate.get_private_key_passphrase() passphrase = certificate.get('passphrase')
if passphrase: if passphrase:
request['passphrase'] = passphrase request['passphrase'] = passphrase
cert_obj = self.vcns.upload_edge_certificate(edge_id, request)[1] cert_obj = self.vcns.upload_edge_certificate(edge_id, request)[1]
@ -166,7 +167,7 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
if certificate: if certificate:
try: try:
edge_cert_id = self._upload_certificate( edge_cert_id = self._upload_certificate(
context, edge_id, listener['default_tls_container_id'], context, edge_id, certificate['ref'],
certificate) certificate)
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
@ -178,7 +179,7 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
try: try:
with locking.LockManager.get_lock(edge_id): with locking.LockManager.get_lock(edge_id):
h = (self.vcns.create_app_profile(edge_id, app_profile))[0] h = (self.vcns.create_app_profile(edge_id, app_profile))[0]
app_profile_id = lb_common.extract_resource_id(h['location']) app_profile_id = lb_v_common.extract_resource_id(h['location'])
except vcns_exc.VcnsApiException: except vcns_exc.VcnsApiException:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
completor(success=False) completor(success=False)
@ -193,7 +194,7 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
try: try:
with locking.LockManager.get_lock(edge_id): with locking.LockManager.get_lock(edge_id):
h = self.vcns.create_vip(edge_id, vse)[0] h = self.vcns.create_vip(edge_id, vse)[0]
edge_vse_id = lb_common.extract_resource_id(h['location']) edge_vse_id = lb_v_common.extract_resource_id(h['location'])
nsxv_db.add_nsxv_lbaas_listener_binding(context.session, nsxv_db.add_nsxv_lbaas_listener_binding(context.session,
lb_id, lb_id,
@ -231,19 +232,19 @@ class EdgeListenerManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
edge_cert_id = None edge_cert_id = None
if certificate: if certificate:
if (old_listener['default_tls_container_id'] != if (lb_common.get_listener_cert_ref(old_listener) !=
new_listener['default_tls_container_id']): lb_common.get_listener_cert_ref(new_listener)):
try: try:
edge_cert_id = self._upload_certificate( edge_cert_id = self._upload_certificate(
context, edge_id, context, edge_id,
new_listener['default_tls_container_id'], certificate['ref'],
certificate) certificate)
except Exception: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
completor(success=False) completor(success=False)
else: else:
cert_binding = nsxv_db.get_nsxv_lbaas_certificate_binding( cert_binding = nsxv_db.get_nsxv_lbaas_certificate_binding(
context.session, new_listener['default_tls_container_id'], context.session, certificate['ref'],
edge_id) edge_id)
edge_cert_id = cert_binding['edge_cert_id'] edge_cert_id = cert_binding['edge_cert_id']

View File

@ -83,14 +83,14 @@ class EdgeListenerManagerFromDict(base_mgr.Nsxv3LoadbalancerBaseManager):
# If so, use that certificate for ssl binding. Otherwise, # If so, use that certificate for ssl binding. Otherwise,
# create a new certificate on NSX. # create a new certificate on NSX.
cert_ids = tm_client.find_cert_with_pem( cert_ids = tm_client.find_cert_with_pem(
certificate.get_certificate()) certificate.get('certificate'))
if cert_ids: if cert_ids:
nsx_cert_id = cert_ids[0] nsx_cert_id = cert_ids[0]
else: else:
nsx_cert_id = tm_client.create_cert( nsx_cert_id = tm_client.create_cert(
certificate.get_certificate(), certificate.get('certificate'),
private_key=certificate.get_private_key(), private_key=certificate.get('private_key'),
passphrase=certificate.get_private_key_passphrase(), passphrase=certificate.get('passphrase'),
tags=tags) tags=tags)
return { return {
'client_ssl_profile_binding': { 'client_ssl_profile_binding': {

View File

@ -22,8 +22,6 @@ from oslo_log import helpers as log_helpers
from oslo_log import log as logging from oslo_log import log as logging
import oslo_messaging as messaging import oslo_messaging as messaging
from oslo_messaging.rpc import dispatcher from oslo_messaging.rpc import dispatcher
import pecan
from stevedore import driver as stevedore_driver
from octavia.api.drivers import utils as oct_utils from octavia.api.drivers import utils as oct_utils
from octavia.db import api as db_apis from octavia.db import api as db_apis
@ -76,7 +74,6 @@ class NSXOctaviaDriver(driver_base.ProviderDriver):
def __init__(self): def __init__(self):
super(NSXOctaviaDriver, self).__init__() super(NSXOctaviaDriver, self).__init__()
self._init_rpc_messaging() self._init_rpc_messaging()
self._init_cert_manager()
self.repositories = repositories.Repositories() self.repositories = repositories.Repositories()
@log_helpers.log_method_call @log_helpers.log_method_call
@ -88,13 +85,6 @@ class NSXOctaviaDriver(driver_base.ProviderDriver):
version='1.0') version='1.0')
self.client = messaging.RPCClient(transport, target) self.client = messaging.RPCClient(transport, target)
@log_helpers.log_method_call
def _init_cert_manager(self):
self.cert_manager = stevedore_driver.DriverManager(
namespace='octavia.cert_manager',
name=cfg.CONF.certificates.cert_manager,
invoke_on_load=True).driver
def get_obj_project_id(self, obj_type, obj_dict): def get_obj_project_id(self, obj_type, obj_dict):
if obj_dict.get('project_id'): if obj_dict.get('project_id'):
return obj_dict['project_id'] return obj_dict['project_id']
@ -309,7 +299,6 @@ class NSXOctaviaDriver(driver_base.ProviderDriver):
# Generate the default pool object # Generate the default pool object
obj_dict['default_pool'] = self._get_pool_dict( obj_dict['default_pool'] = self._get_pool_dict(
obj_dict['default_pool_id'], is_update, project_id) obj_dict['default_pool_id'], is_update, project_id)
# TODO(asarfaty): add default_tls_container_id
elif obj_type == 'Pool': elif obj_type == 'Pool':
if 'listener' not in obj_dict: if 'listener' not in obj_dict:
@ -395,15 +384,21 @@ class NSXOctaviaDriver(driver_base.ProviderDriver):
'new_loadbalancer': new_dict} 'new_loadbalancer': new_dict}
self.client.cast({}, 'loadbalancer_update', **kw) self.client.cast({}, 'loadbalancer_update', **kw)
def _create_lb_certificate(self, listener_dict):
# Extract Octavia certificate data into a dict which is readable by
# the listener_mgr
if listener_dict.get('default_tls_container_ref'):
cert_data = listener_dict.get('default_tls_container_data', {})
return {'ref': listener_dict.get('default_tls_container_ref'),
'certificate': cert_data.get('certificate'),
'private_key': cert_data.get('private_key'),
'passphrase': cert_data.get('passphrase')}
# Listener # Listener
@log_helpers.log_method_call @log_helpers.log_method_call
def listener_create(self, listener): def listener_create(self, listener):
cert = None
dict_list = self.obj_to_dict(listener) dict_list = self.obj_to_dict(listener)
if dict_list.get('tls_certificate_id'): cert = self._create_lb_certificate(dict_list)
context = pecan.request.context.get('octavia_context')
cert = self.cert_manager.get_cert(context,
dict_list['tls_certificate_id'])
kw = {'listener': dict_list, 'cert': cert} kw = {'listener': dict_list, 'cert': cert}
self.client.cast({}, 'listener_create', **kw) self.client.cast({}, 'listener_create', **kw)
@ -419,11 +414,7 @@ class NSXOctaviaDriver(driver_base.ProviderDriver):
new_dict.update(self.obj_to_dict( new_dict.update(self.obj_to_dict(
new_listener, is_update=True, new_listener, is_update=True,
project_id=old_dict.get('project_id'))) project_id=old_dict.get('project_id')))
cert = None cert = self._create_lb_certificate(new_dict)
if new_dict.get('tls_certificate_id'):
context = pecan.request.context.get('octavia_context')
cert = self.cert_manager.get_cert(context,
new_dict['tls_certificate_id'])
kw = {'old_listener': old_dict, kw = {'old_listener': old_dict,
'new_listener': new_dict, 'new_listener': new_dict,
'cert': cert} 'cert': cert}

View File

@ -47,8 +47,7 @@ class TestNsxProviderDriver(testtools.TestCase):
if not code_ok: if not code_ok:
return return
# init the NSX driver without the RPC & certificate # init the NSX driver without the RPC & certificate
with mock.patch(DRIVER + '._init_rpc_messaging'), \ with mock.patch(DRIVER + '._init_rpc_messaging'):
mock.patch(DRIVER + '._init_cert_manager'):
self.driver = driver.NSXOctaviaDriver() self.driver = driver.NSXOctaviaDriver()
self.driver.client = mock.Mock() self.driver.client = mock.Mock()
@ -66,6 +65,11 @@ class TestNsxProviderDriver(testtools.TestCase):
self.l7rule_id = uuidutils.generate_uuid() self.l7rule_id = uuidutils.generate_uuid()
self.project_id = uuidutils.generate_uuid() self.project_id = uuidutils.generate_uuid()
self.default_tls_container_ref = uuidutils.generate_uuid() self.default_tls_container_ref = uuidutils.generate_uuid()
self.default_tls_container_data = {
'ref': self.default_tls_container_ref,
'certificate': 'cert_text',
'private_key': 'pk_text',
'passphrase': 'pp_text'}
self.sni_container_ref_1 = uuidutils.generate_uuid() self.sni_container_ref_1 = uuidutils.generate_uuid()
self.sni_container_ref_2 = uuidutils.generate_uuid() self.sni_container_ref_2 = uuidutils.generate_uuid()
@ -134,7 +138,7 @@ class TestNsxProviderDriver(testtools.TestCase):
connection_limit=5, connection_limit=5,
default_pool=self.ref_pool, default_pool=self.ref_pool,
default_pool_id=self.pool_id, default_pool_id=self.pool_id,
default_tls_container_data='default_cert_data', default_tls_container_data=self.default_tls_container_data,
default_tls_container_ref=self.default_tls_container_ref, default_tls_container_ref=self.default_tls_container_ref,
description='The listener', description='The listener',
insert_headers={'X-Forwarded-For': 'true'}, insert_headers={'X-Forwarded-For': 'true'},
@ -222,7 +226,8 @@ class TestNsxProviderDriver(testtools.TestCase):
def test_listener_create(self): def test_listener_create(self):
with mock.patch.object(self.driver.client, 'cast') as cast_method: with mock.patch.object(self.driver.client, 'cast') as cast_method:
self.driver.listener_create(self.ref_listener) self.driver.listener_create(self.ref_listener)
cast_method.assert_called_with({}, 'listener_create', cert=None, cast_method.assert_called_with(
{}, 'listener_create', cert=self.default_tls_container_data,
listener=mock.ANY) listener=mock.ANY)
driver_obj = cast_method.call_args[1]['listener'] driver_obj = cast_method.call_args[1]['listener']
self.assertIn('id', driver_obj) self.assertIn('id', driver_obj)
@ -255,7 +260,9 @@ class TestNsxProviderDriver(testtools.TestCase):
def test_listener_update(self): def test_listener_update(self):
with mock.patch.object(self.driver.client, 'cast') as cast_method: with mock.patch.object(self.driver.client, 'cast') as cast_method:
self.driver.listener_update(self.ref_listener, self.ref_listener) self.driver.listener_update(self.ref_listener, self.ref_listener)
cast_method.assert_called_with({}, 'listener_update', cert=None, cast_method.assert_called_with(
{}, 'listener_update',
cert=self.default_tls_container_data,
old_listener=mock.ANY, old_listener=mock.ANY,
new_listener=mock.ANY) new_listener=mock.ANY)
driver_obj = cast_method.call_args[1]['new_listener'] driver_obj = cast_method.call_args[1]['new_listener']