Merge "NSXv3: Fix TERMINATED_HTTPS listener"

This commit is contained in:
Zuul 2017-11-05 20:58:35 +00:00 committed by Gerrit Code Review
commit d21223ebbe
4 changed files with 163 additions and 13 deletions

View File

@ -124,6 +124,8 @@ NSX_V3_FW_DEFAULT_NS_GROUP = 'os_default_section_ns_group'
NSX_V3_DEFAULT_SECTION = 'OS-Default-Section'
NSX_V3_EXCLUDED_PORT_NSGROUP_NAME = 'neutron_excluded_port_nsgroup'
NSX_V3_NON_VIF_PROFILE = 'nsx-default-switch-security-non-vif-profile'
NSX_V3_SERVER_SSL_PROFILE = 'nsx-default-server-ssl-profile'
NSX_V3_CLIENT_SSL_PROFILE = 'nsx-default-client-ssl-profile'
def inject_headers():
@ -359,6 +361,17 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
NSX_V3_NON_VIF_PROFILE)[0]
self._no_switch_security = profile_client.build_switch_profile_ids(
profile_client, no_switch_security_prof)[0]
self.server_ssl_profile = None
self.client_ssl_profile = None
# Only create LB profiles when nsxv3 version >= 2.1.0
if self.nsxlib.feature_supported(nsxlib_consts.FEATURE_LOAD_BALANCER):
LOG.debug("Initializing NSX v3 Load Balancer default profiles")
try:
self._init_lb_profiles()
except Exception as e:
msg = (_("Unable to initialize NSX v3 lb profiles: "
"Reason: %(reason)s") % {'reason': str(e)})
raise nsx_exc.NsxPluginException(err_msg=msg)
def _translate_configured_names_to_uuids(self):
# If using tags to find the objects, make sure tag scope is configured
@ -530,6 +543,35 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
profile_id=profile[0]['id']) if profile else None
return self._mac_learning_profile
def _init_lb_profiles(self):
with locking.LockManager.get_lock('nsxv3_lb_profiles_init'):
lb_profiles = self._get_lb_profiles()
if not lb_profiles.get('client_ssl_profile'):
self.nsxlib.load_balancer.client_ssl_profile.create(
NSX_V3_CLIENT_SSL_PROFILE,
'Neutron LB Client SSL Profile',
tags=self.nsxlib.build_v3_api_version_tag())
if not lb_profiles.get('server_ssl_profile'):
self.nsxlib.load_balancer.server_ssl_profile.create(
NSX_V3_SERVER_SSL_PROFILE,
'Neutron LB Server SSL Profile',
tags=self.nsxlib.build_v3_api_version_tag())
def _get_lb_profiles(self):
if not self.client_ssl_profile:
ssl_profile_client = self.nsxlib.load_balancer.client_ssl_profile
profile = ssl_profile_client.find_by_display_name(
NSX_V3_CLIENT_SSL_PROFILE)
self.client_ssl_profile = profile[0]['id'] if profile else None
if not self.server_ssl_profile:
ssl_profile_client = self.nsxlib.load_balancer.server_ssl_profile
profile = ssl_profile_client.find_by_display_name(
NSX_V3_SERVER_SSL_PROFILE)
self.server_ssl_profile = profile[0]['id'] if profile else None
return {'client_ssl_profile': self.client_ssl_profile,
'server_ssl_profile': self.server_ssl_profile}
def _get_port_security_profile_id(self):
return self.nsxlib.switching_profile.build_switch_profile_ids(
self.nsxlib.switching_profile, self._psec_profile)[0]

View File

@ -98,6 +98,7 @@ LB_STATS_MAP = {'active_connections': 'current_sessions',
'total_connections': 'total_sessions'}
LR_ROUTER_TYPE = 'os-neutron-router-id'
LR_PORT_TYPE = 'os-neutron-rport-id'
LB_CERT_RESOURCE_TYPE = ['certificate_signed', 'certificate_self_signed']
DEFAULT_LB_SIZE = 'SMALL'
LB_FLAVOR_SIZES = ['SMALL', 'MEDIUM', 'LARGE', 'small', 'medium', 'large']
LB_RULE_MATCH_TYPE = {

View File

@ -34,10 +34,51 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
def __init__(self):
super(EdgeListenerManager, self).__init__()
def _get_virtual_server_kwargs(self, context, listener, vs_name, tags,
app_profile_id, certificate=None):
kwargs = {'display_name': vs_name,
'tags': tags,
'enabled': listener.admin_state_up,
'ip_address': listener.loadbalancer.vip_address,
'port': listener.protocol_port,
'application_profile_id': app_profile_id}
if listener.connection_limit != -1:
kwargs['max_concurrent_connections'] = \
listener.connection_limit
if listener.default_pool_id:
pool_binding = nsx_db.get_nsx_lbaas_pool_binding(
context.session, listener.loadbalancer.id,
listener.default_pool_id)
if pool_binding:
kwargs['pool_id'] = pool_binding.get('lb_pool_id')
ssl_profile_binding = self._get_ssl_profile_binding(
tags, certificate=certificate)
if (listener.protocol == lb_const.LB_PROTOCOL_TERMINATED_HTTPS and
ssl_profile_binding):
kwargs.update(ssl_profile_binding)
return kwargs
def _get_ssl_profile_binding(self, tags, certificate=None):
tm_client = self.core_plugin.nsxlib.trust_management
nsx_cert_id = None
ssl_profile_binding = None
if certificate:
nsx_cert_id = tm_client.create_cert(
certificate.get_certificate(),
private_key=certificate.get_private_key(),
passphrase=certificate.get_private_key_passphrase(),
tags=tags)
ssl_profile_binding = {
'client_ssl_profile_binding': {
'ssl_profile_id': self.core_plugin.client_ssl_profile,
'default_certificate_id': nsx_cert_id
}
}
return ssl_profile_binding
@log_helpers.log_method_call
def create(self, context, listener, certificate=None):
lb_id = listener.loadbalancer_id
vip_address = listener.loadbalancer.vip_address
load_balancer = self.core_plugin.nsxlib.load_balancer
app_client = load_balancer.application_profile
vs_client = load_balancer.virtual_server
@ -51,9 +92,12 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
'tag': listener.loadbalancer.name[:utils.MAX_TAG_LEN]})
tags.append({'scope': 'os-lbaas-lb-id',
'tag': lb_id})
if listener.protocol == 'HTTP' or listener.protocol == 'HTTPS':
if (listener.protocol == lb_const.LB_PROTOCOL_HTTP or
listener.protocol == lb_const.LB_PROTOCOL_TERMINATED_HTTPS):
profile_type = lb_const.LB_HTTP_PROFILE
elif listener.protocol == 'TCP':
elif (listener.protocol == lb_const.LB_PROTOCOL_TCP or
listener.protocol == lb_const.LB_PROTOCOL_HTTPS):
profile_type = lb_const.LB_TCP_PROFILE
else:
msg = (_('Cannot create listener %(listener)s with '
@ -65,13 +109,9 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
app_profile = app_client.create(
display_name=vs_name, resource_type=profile_type, tags=tags)
app_profile_id = app_profile['id']
virtual_server = vs_client.create(
display_name=vs_name,
tags=tags,
enabled=listener.admin_state_up,
ip_address=vip_address,
port=listener.protocol_port,
application_profile_id=app_profile_id)
kwargs = self._get_virtual_server_kwargs(
context, listener, vs_name, tags, app_profile_id, certificate)
virtual_server = vs_client.create(**kwargs)
except nsxlib_exc.ManagerError:
self.lbv2_driver.listener.failed_completion(context, listener)
msg = _('Failed to create virtual server at NSX backend')
@ -164,6 +204,23 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
msg = (_('Failed to delete application profile: %(app)s') %
{'app': app_profile_id})
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
# Delete imported NSX cert if there is any
cert_tags = [{'scope': lb_const.LB_LISTENER_TYPE,
'tag': listener.id}]
results = self.core_plugin.nsxlib.search_by_tags(
tags=cert_tags)
# Only delete object related to certificate used by listener
for obj in results['results']:
if obj.get('resource_type') in lb_const.LB_CERT_RESOURCE_TYPE:
tm_client = self.core_plugin.nsxlib.trust_management
try:
tm_client.delete_cert(obj['id'])
except nsxlib_exc.ManagerError:
LOG.error("Exception thrown when trying to delete "
"certificate: %(cert)s",
{'cert': obj['id']})
nsx_db.delete_nsx_lbaas_listener_binding(
context.session, lb_id, listener.id)

View File

@ -103,6 +103,8 @@ L7RULE_BINDING = {'loadbalancer_id': LB_ID,
'lb_vs_id': LB_VS_ID,
'lb_rule_id': LB_RULE_ID}
FAKE_CERT = {'id': 'cert-xyz'}
class BaseTestEdgeLbaasV2(base.BaseTestCase):
def _tested_entity(self):
@ -127,6 +129,12 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
'listener1', '', None, LB_ID,
'HTTP', protocol_port=80,
loadbalancer=self.lb)
self.https_listener = lb_models.Listener(
LISTENER_ID, LB_TENANT_ID, 'listener1', '', None, LB_ID,
'HTTPS', protocol_port=443, loadbalancer=self.lb)
self.terminated_https_listener = lb_models.Listener(
LISTENER_ID, LB_TENANT_ID, 'listener1', '', None, LB_ID,
'TERMINATED_HTTPS', protocol_port=443, loadbalancer=self.lb)
self.pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
None, 'HTTP', 'ROUND_ROBIN',
loadbalancer_id=LB_ID,
@ -182,6 +190,8 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
'monitor').start()
self.rule_client = mock.patch.object(load_balancer,
'rule').start()
self.tm_client = mock.patch.object(nsxlib,
'trust_management').start()
def _unpatch_lb_plugin(self, lb_plugin, manager):
setattr(lb_plugin, manager, self.real_manager)
@ -256,7 +266,7 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
def _tested_entity(self):
return 'listener'
def test_create(self):
def _create_listener(self, protocol='HTTP'):
with mock.patch.object(self.app_client, 'create'
) as mock_create_app_profile, \
mock.patch.object(self.vs_client, 'create'
@ -270,8 +280,11 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
mock_create_app_profile.return_value = {'id': APP_PROFILE_ID}
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
mock_get_lb_binding.return_value = LB_BINDING
listener = self.listener
if protocol == 'HTTPS':
listener = self.https_listener
self.edge_driver.listener.create(self.context, self.listener)
self.edge_driver.listener.create(self.context, listener)
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
LB_VS_ID)
@ -282,7 +295,44 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
mock_successful_completion = (
self.lbv2_driver.listener.successful_completion)
mock_successful_completion.assert_called_with(self.context,
self.listener)
listener)
def test_create_http_listener(self):
self._create_listener()
def test_create_https_listener(self):
self._create_listener(protocol='HTTPS')
def test_create_terminated_https(self):
with mock.patch.object(self.tm_client, 'create_cert'
) as mock_create_cert, \
mock.patch.object(self.app_client, 'create'
) as mock_create_app_profile, \
mock.patch.object(self.vs_client, 'create'
) as mock_create_virtual_server, \
mock.patch.object(nsx_db, 'get_nsx_lbaas_loadbalancer_binding'
) as mock_get_lb_binding, \
mock.patch.object(self.service_client, 'add_virtual_server'
) as mock_add_virtual_server, \
mock.patch.object(nsx_db, 'add_nsx_lbaas_listener_binding'
) as mock_add_listener_binding:
mock_create_cert.return_value = FAKE_CERT['id']
mock_create_app_profile.return_value = {'id': APP_PROFILE_ID}
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
mock_get_lb_binding.return_value = LB_BINDING
self.edge_driver.listener.create(self.context,
self.terminated_https_listener)
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
LB_VS_ID)
mock_add_listener_binding.assert_called_with(
self.context.session, LB_ID, LISTENER_ID, APP_PROFILE_ID,
LB_VS_ID)
mock_successful_completion = (
self.lbv2_driver.listener.successful_completion)
mock_successful_completion.assert_called_with(
self.context, self.terminated_https_listener)
def test_update(self):
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,