Merge "NSXv3: Fix TERMINATED_HTTPS listener"
This commit is contained in:
commit
d21223ebbe
@ -124,6 +124,8 @@ NSX_V3_FW_DEFAULT_NS_GROUP = 'os_default_section_ns_group'
|
|||||||
NSX_V3_DEFAULT_SECTION = 'OS-Default-Section'
|
NSX_V3_DEFAULT_SECTION = 'OS-Default-Section'
|
||||||
NSX_V3_EXCLUDED_PORT_NSGROUP_NAME = 'neutron_excluded_port_nsgroup'
|
NSX_V3_EXCLUDED_PORT_NSGROUP_NAME = 'neutron_excluded_port_nsgroup'
|
||||||
NSX_V3_NON_VIF_PROFILE = 'nsx-default-switch-security-non-vif-profile'
|
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():
|
def inject_headers():
|
||||||
@ -359,6 +361,17 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
|||||||
NSX_V3_NON_VIF_PROFILE)[0]
|
NSX_V3_NON_VIF_PROFILE)[0]
|
||||||
self._no_switch_security = profile_client.build_switch_profile_ids(
|
self._no_switch_security = profile_client.build_switch_profile_ids(
|
||||||
profile_client, no_switch_security_prof)[0]
|
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):
|
def _translate_configured_names_to_uuids(self):
|
||||||
# If using tags to find the objects, make sure tag scope is configured
|
# 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
|
profile_id=profile[0]['id']) if profile else None
|
||||||
return self._mac_learning_profile
|
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):
|
def _get_port_security_profile_id(self):
|
||||||
return self.nsxlib.switching_profile.build_switch_profile_ids(
|
return self.nsxlib.switching_profile.build_switch_profile_ids(
|
||||||
self.nsxlib.switching_profile, self._psec_profile)[0]
|
self.nsxlib.switching_profile, self._psec_profile)[0]
|
||||||
|
@ -98,6 +98,7 @@ LB_STATS_MAP = {'active_connections': 'current_sessions',
|
|||||||
'total_connections': 'total_sessions'}
|
'total_connections': 'total_sessions'}
|
||||||
LR_ROUTER_TYPE = 'os-neutron-router-id'
|
LR_ROUTER_TYPE = 'os-neutron-router-id'
|
||||||
LR_PORT_TYPE = 'os-neutron-rport-id'
|
LR_PORT_TYPE = 'os-neutron-rport-id'
|
||||||
|
LB_CERT_RESOURCE_TYPE = ['certificate_signed', 'certificate_self_signed']
|
||||||
DEFAULT_LB_SIZE = 'SMALL'
|
DEFAULT_LB_SIZE = 'SMALL'
|
||||||
LB_FLAVOR_SIZES = ['SMALL', 'MEDIUM', 'LARGE', 'small', 'medium', 'large']
|
LB_FLAVOR_SIZES = ['SMALL', 'MEDIUM', 'LARGE', 'small', 'medium', 'large']
|
||||||
LB_RULE_MATCH_TYPE = {
|
LB_RULE_MATCH_TYPE = {
|
||||||
|
@ -34,10 +34,51 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(EdgeListenerManager, self).__init__()
|
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
|
@log_helpers.log_method_call
|
||||||
def create(self, context, listener, certificate=None):
|
def create(self, context, listener, certificate=None):
|
||||||
lb_id = listener.loadbalancer_id
|
lb_id = listener.loadbalancer_id
|
||||||
vip_address = listener.loadbalancer.vip_address
|
|
||||||
load_balancer = self.core_plugin.nsxlib.load_balancer
|
load_balancer = self.core_plugin.nsxlib.load_balancer
|
||||||
app_client = load_balancer.application_profile
|
app_client = load_balancer.application_profile
|
||||||
vs_client = load_balancer.virtual_server
|
vs_client = load_balancer.virtual_server
|
||||||
@ -51,9 +92,12 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
'tag': listener.loadbalancer.name[:utils.MAX_TAG_LEN]})
|
'tag': listener.loadbalancer.name[:utils.MAX_TAG_LEN]})
|
||||||
tags.append({'scope': 'os-lbaas-lb-id',
|
tags.append({'scope': 'os-lbaas-lb-id',
|
||||||
'tag': 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
|
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
|
profile_type = lb_const.LB_TCP_PROFILE
|
||||||
else:
|
else:
|
||||||
msg = (_('Cannot create listener %(listener)s with '
|
msg = (_('Cannot create listener %(listener)s with '
|
||||||
@ -65,13 +109,9 @@ class EdgeListenerManager(base_mgr.Nsxv3LoadbalancerBaseManager):
|
|||||||
app_profile = app_client.create(
|
app_profile = app_client.create(
|
||||||
display_name=vs_name, resource_type=profile_type, tags=tags)
|
display_name=vs_name, resource_type=profile_type, tags=tags)
|
||||||
app_profile_id = app_profile['id']
|
app_profile_id = app_profile['id']
|
||||||
virtual_server = vs_client.create(
|
kwargs = self._get_virtual_server_kwargs(
|
||||||
display_name=vs_name,
|
context, listener, vs_name, tags, app_profile_id, certificate)
|
||||||
tags=tags,
|
virtual_server = vs_client.create(**kwargs)
|
||||||
enabled=listener.admin_state_up,
|
|
||||||
ip_address=vip_address,
|
|
||||||
port=listener.protocol_port,
|
|
||||||
application_profile_id=app_profile_id)
|
|
||||||
except nsxlib_exc.ManagerError:
|
except nsxlib_exc.ManagerError:
|
||||||
self.lbv2_driver.listener.failed_completion(context, listener)
|
self.lbv2_driver.listener.failed_completion(context, listener)
|
||||||
msg = _('Failed to create virtual server at NSX backend')
|
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') %
|
msg = (_('Failed to delete application profile: %(app)s') %
|
||||||
{'app': app_profile_id})
|
{'app': app_profile_id})
|
||||||
raise n_exc.BadRequest(resource='lbaas-listener', msg=msg)
|
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(
|
nsx_db.delete_nsx_lbaas_listener_binding(
|
||||||
context.session, lb_id, listener.id)
|
context.session, lb_id, listener.id)
|
||||||
|
|
||||||
|
@ -103,6 +103,8 @@ L7RULE_BINDING = {'loadbalancer_id': LB_ID,
|
|||||||
'lb_vs_id': LB_VS_ID,
|
'lb_vs_id': LB_VS_ID,
|
||||||
'lb_rule_id': LB_RULE_ID}
|
'lb_rule_id': LB_RULE_ID}
|
||||||
|
|
||||||
|
FAKE_CERT = {'id': 'cert-xyz'}
|
||||||
|
|
||||||
|
|
||||||
class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
||||||
def _tested_entity(self):
|
def _tested_entity(self):
|
||||||
@ -127,6 +129,12 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
|||||||
'listener1', '', None, LB_ID,
|
'listener1', '', None, LB_ID,
|
||||||
'HTTP', protocol_port=80,
|
'HTTP', protocol_port=80,
|
||||||
loadbalancer=self.lb)
|
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', '',
|
self.pool = lb_models.Pool(POOL_ID, LB_TENANT_ID, 'pool1', '',
|
||||||
None, 'HTTP', 'ROUND_ROBIN',
|
None, 'HTTP', 'ROUND_ROBIN',
|
||||||
loadbalancer_id=LB_ID,
|
loadbalancer_id=LB_ID,
|
||||||
@ -182,6 +190,8 @@ class BaseTestEdgeLbaasV2(base.BaseTestCase):
|
|||||||
'monitor').start()
|
'monitor').start()
|
||||||
self.rule_client = mock.patch.object(load_balancer,
|
self.rule_client = mock.patch.object(load_balancer,
|
||||||
'rule').start()
|
'rule').start()
|
||||||
|
self.tm_client = mock.patch.object(nsxlib,
|
||||||
|
'trust_management').start()
|
||||||
|
|
||||||
def _unpatch_lb_plugin(self, lb_plugin, manager):
|
def _unpatch_lb_plugin(self, lb_plugin, manager):
|
||||||
setattr(lb_plugin, manager, self.real_manager)
|
setattr(lb_plugin, manager, self.real_manager)
|
||||||
@ -256,7 +266,7 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
|||||||
def _tested_entity(self):
|
def _tested_entity(self):
|
||||||
return 'listener'
|
return 'listener'
|
||||||
|
|
||||||
def test_create(self):
|
def _create_listener(self, protocol='HTTP'):
|
||||||
with mock.patch.object(self.app_client, 'create'
|
with mock.patch.object(self.app_client, 'create'
|
||||||
) as mock_create_app_profile, \
|
) as mock_create_app_profile, \
|
||||||
mock.patch.object(self.vs_client, 'create'
|
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_app_profile.return_value = {'id': APP_PROFILE_ID}
|
||||||
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
|
mock_create_virtual_server.return_value = {'id': LB_VS_ID}
|
||||||
mock_get_lb_binding.return_value = LB_BINDING
|
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,
|
mock_add_virtual_server.assert_called_with(LB_SERVICE_ID,
|
||||||
LB_VS_ID)
|
LB_VS_ID)
|
||||||
@ -282,7 +295,44 @@ class TestEdgeLbaasV2Listener(BaseTestEdgeLbaasV2):
|
|||||||
mock_successful_completion = (
|
mock_successful_completion = (
|
||||||
self.lbv2_driver.listener.successful_completion)
|
self.lbv2_driver.listener.successful_completion)
|
||||||
mock_successful_completion.assert_called_with(self.context,
|
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):
|
def test_update(self):
|
||||||
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
new_listener = lb_models.Listener(LISTENER_ID, LB_TENANT_ID,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user