Merge "NSXv: Remove router dependency for LBaaS"
This commit is contained in:
commit
6ccae5b9ae
@ -23,6 +23,7 @@ DHCP_EDGE_PREFIX = 'dhcp-'
|
|||||||
ROUTER_EDGE_PREFIX = 'router-'
|
ROUTER_EDGE_PREFIX = 'router-'
|
||||||
PLR_EDGE_PREFIX = 'plr-'
|
PLR_EDGE_PREFIX = 'plr-'
|
||||||
BACKUP_ROUTER_PREFIX = 'backup-'
|
BACKUP_ROUTER_PREFIX = 'backup-'
|
||||||
|
LB_EDGE_PREFIX = 'lb-'
|
||||||
EDGE_NAME_LEN = 20
|
EDGE_NAME_LEN = 20
|
||||||
|
|
||||||
# Interface
|
# Interface
|
||||||
@ -59,7 +60,8 @@ SUFFIX_LENGTH = 8
|
|||||||
#Edge size
|
#Edge size
|
||||||
SERVICE_SIZE_MAPPING = {
|
SERVICE_SIZE_MAPPING = {
|
||||||
'router': nsxv_constants.COMPACT,
|
'router': nsxv_constants.COMPACT,
|
||||||
'dhcp': nsxv_constants.COMPACT
|
'dhcp': nsxv_constants.COMPACT,
|
||||||
|
'lb': nsxv_constants.COMPACT
|
||||||
}
|
}
|
||||||
ALLOWED_EDGE_SIZES = (nsxv_constants.COMPACT,
|
ALLOWED_EDGE_SIZES = (nsxv_constants.COMPACT,
|
||||||
nsxv_constants.LARGE,
|
nsxv_constants.LARGE,
|
||||||
|
@ -814,6 +814,15 @@ class EdgeManager(object):
|
|||||||
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
|
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
|
||||||
availability_zone=availability_zone)
|
availability_zone=availability_zone)
|
||||||
|
|
||||||
|
def allocate_lb_edge_appliance(
|
||||||
|
self, context, resource_id, availability_zone,
|
||||||
|
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['lb']):
|
||||||
|
|
||||||
|
return self._allocate_edge_appliance(
|
||||||
|
context, resource_id, resource_id,
|
||||||
|
appliance_size=appliance_size,
|
||||||
|
availability_zone=availability_zone)
|
||||||
|
|
||||||
def _free_dhcp_edge_appliance(self, context, network_id):
|
def _free_dhcp_edge_appliance(self, context, network_id):
|
||||||
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||||
|
|
||||||
@ -855,6 +864,8 @@ class EdgeManager(object):
|
|||||||
self.update_syslog_by_flavor(context,
|
self.update_syslog_by_flavor(context,
|
||||||
lrouter['id'], lrouter['flavor_id'], edge_id)
|
lrouter['id'], lrouter['flavor_id'], edge_id)
|
||||||
|
|
||||||
|
return edge_id
|
||||||
|
|
||||||
def delete_lrouter(self, context, router_id, dist=False):
|
def delete_lrouter(self, context, router_id, dist=False):
|
||||||
self._free_edge_appliance(context, router_id)
|
self._free_edge_appliance(context, router_id)
|
||||||
|
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
|
|
||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
|
from neutron_lib import constants
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
|
|
||||||
from vmware_nsx._i18n import _
|
from vmware_nsx._i18n import _
|
||||||
from vmware_nsx.common import locking
|
from vmware_nsx.common import locking
|
||||||
from vmware_nsx.db import nsxv_db
|
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
|
||||||
|
|
||||||
MEMBER_ID_PFX = 'member-'
|
MEMBER_ID_PFX = 'member-'
|
||||||
|
|
||||||
@ -28,25 +29,49 @@ def get_member_id(member_id):
|
|||||||
return MEMBER_ID_PFX + member_id
|
return MEMBER_ID_PFX + member_id
|
||||||
|
|
||||||
|
|
||||||
def get_lbaas_edge_id_for_subnet(context, plugin, subnet_id, tenant_id):
|
def get_lb_resource_id(lb_id):
|
||||||
"""
|
return ('lbaas-' + lb_id)[:36]
|
||||||
Grab the id of an Edge appliance that is connected to subnet_id.
|
|
||||||
"""
|
|
||||||
subnet = plugin.get_subnet(context, subnet_id)
|
|
||||||
net_id = subnet.get('network_id')
|
|
||||||
filters = {'network_id': [net_id],
|
|
||||||
'device_owner': ['network:router_interface'],
|
|
||||||
'tenant_id': [tenant_id]}
|
|
||||||
attached_routers = plugin.get_ports(context.elevated(),
|
|
||||||
filters=filters,
|
|
||||||
fields=['device_id'])
|
|
||||||
|
|
||||||
for attached_router in attached_routers:
|
|
||||||
router = plugin.get_router(context, attached_router['device_id'])
|
def get_lbaas_edge_id(context, plugin, lb_id, vip_addr, subnet_id, tenant_id):
|
||||||
if router.get('router_type') == 'exclusive':
|
subnet = plugin.get_subnet(context, subnet_id)
|
||||||
rtr_bindings = nsxv_db.get_nsxv_router_binding(context.session,
|
network_id = subnet.get('network_id')
|
||||||
router['id'])
|
availability_zone = plugin.get_network_az(context, network_id)
|
||||||
return rtr_bindings['edge_id']
|
|
||||||
|
resource_id = get_lb_resource_id(lb_id)
|
||||||
|
|
||||||
|
edge_id = plugin.edge_manager.allocate_lb_edge_appliance(
|
||||||
|
context, resource_id, availability_zone=availability_zone)
|
||||||
|
|
||||||
|
port_dict = {'name': 'lb_if-' + lb_id,
|
||||||
|
'admin_state_up': True,
|
||||||
|
'network_id': network_id,
|
||||||
|
'tenant_id': tenant_id,
|
||||||
|
'fixed_ips': [{'subnet_id': subnet['id']}],
|
||||||
|
'device_owner': constants.DEVICE_OWNER_NEUTRON_PREFIX + 'LB',
|
||||||
|
'device_id': lb_id,
|
||||||
|
'mac_address': constants.ATTR_NOT_SPECIFIED
|
||||||
|
}
|
||||||
|
port = plugin.base_create_port(context, {'port': port_dict})
|
||||||
|
ip_addr = port['fixed_ips'][0]['ip_address']
|
||||||
|
net = netaddr.IPNetwork(subnet['cidr'])
|
||||||
|
|
||||||
|
address_groups = [{'primaryAddress': ip_addr,
|
||||||
|
'subnetPrefixLength': str(net.prefixlen),
|
||||||
|
'subnetMask': str(net.netmask),
|
||||||
|
'secondaryAddresses': {
|
||||||
|
'type': 'secondary_addresses',
|
||||||
|
'ipAddress': [vip_addr]}
|
||||||
|
}]
|
||||||
|
edge_utils.update_internal_interface(
|
||||||
|
plugin.nsx_v, context, resource_id,
|
||||||
|
network_id, address_groups)
|
||||||
|
|
||||||
|
gw_ip = subnet.get('gateway_ip')
|
||||||
|
if gw_ip:
|
||||||
|
plugin.nsx_v.update_routes(edge_id, gw_ip, [])
|
||||||
|
|
||||||
|
return edge_id
|
||||||
|
|
||||||
|
|
||||||
def find_address_in_same_subnet(ip_addr, address_groups):
|
def find_address_in_same_subnet(ip_addr, address_groups):
|
||||||
|
@ -13,6 +13,10 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from neutron.callbacks import events
|
||||||
|
from neutron.callbacks import registry
|
||||||
|
from neutron.callbacks import resources
|
||||||
|
from neutron_lib import constants
|
||||||
from neutron_lib import exceptions as n_exc
|
from neutron_lib import exceptions as n_exc
|
||||||
from oslo_log import helpers as log_helpers
|
from oslo_log import helpers as log_helpers
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
@ -31,15 +35,20 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def __init__(self, vcns_driver):
|
def __init__(self, vcns_driver):
|
||||||
super(EdgeLoadBalancerManager, self).__init__(vcns_driver)
|
super(EdgeLoadBalancerManager, self).__init__(vcns_driver)
|
||||||
|
registry.subscribe(
|
||||||
|
self._handle_subnet_gw_change,
|
||||||
|
resources.SUBNET_GATEWAY, events.AFTER_UPDATE)
|
||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def create(self, context, lb):
|
def create(self, context, lb):
|
||||||
edge_id = lb_common.get_lbaas_edge_id_for_subnet(
|
edge_id = lb_common.get_lbaas_edge_id(
|
||||||
context, self.core_plugin, lb.vip_subnet_id, lb.tenant_id)
|
context, self.core_plugin, lb.id, lb.vip_address, lb.vip_subnet_id,
|
||||||
|
lb.tenant_id)
|
||||||
|
|
||||||
if not edge_id:
|
if not edge_id:
|
||||||
msg = _(
|
msg = _('Failed to allocate Edge on subnet %(sub)s for '
|
||||||
'No suitable Edge found for subnet %s') % lb.vip_subnet_id
|
'loadbalancer %(lb)s') % {'sub': lb.vip_subnet_id,
|
||||||
|
'lb': lb.id}
|
||||||
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -47,8 +56,6 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
context.session, edge_id):
|
context.session, edge_id):
|
||||||
lb_common.enable_edge_acceleration(self.vcns, edge_id)
|
lb_common.enable_edge_acceleration(self.vcns, edge_id)
|
||||||
|
|
||||||
lb_common.add_vip_as_secondary_ip(self.vcns, edge_id,
|
|
||||||
lb.vip_address)
|
|
||||||
edge_fw_rule_id = lb_common.add_vip_fw_rule(
|
edge_fw_rule_id = lb_common.add_vip_fw_rule(
|
||||||
self.vcns, edge_id, lb.id, lb.vip_address)
|
self.vcns, edge_id, lb.id, lb.vip_address)
|
||||||
|
|
||||||
@ -68,22 +75,43 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
|
|
||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def delete(self, context, lb):
|
def delete(self, context, lb):
|
||||||
|
# Discard any ports which are associated with LB
|
||||||
|
filters = {
|
||||||
|
'device_id': [lb.id],
|
||||||
|
'device_owner': [constants.DEVICE_OWNER_NEUTRON_PREFIX + 'LB']}
|
||||||
|
lb_ports = self.core_plugin.get_ports(context.elevated(),
|
||||||
|
filters=filters)
|
||||||
|
for lb_port in lb_ports:
|
||||||
|
self.core_plugin.delete_port(context.elevated(), lb_port['id'])
|
||||||
|
|
||||||
binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
||||||
context.session, lb.id)
|
context.session, lb.id)
|
||||||
if binding:
|
if binding:
|
||||||
|
edge_binding = nsxv_db.get_nsxv_router_binding_by_edge(
|
||||||
|
context.session, binding['edge_id'])
|
||||||
|
|
||||||
|
if edge_binding:
|
||||||
|
if edge_binding['router_id'].startswith('lbaas-'):
|
||||||
|
resource_id = lb_common.get_lb_resource_id(lb.id)
|
||||||
|
self.core_plugin.edge_manager.delete_lrouter(
|
||||||
|
context, resource_id, dist=False)
|
||||||
|
else:
|
||||||
|
# Edge was created on an exclusive router with the old code
|
||||||
try:
|
try:
|
||||||
lb_common.del_vip_fw_rule(self.vcns, binding['edge_id'],
|
lb_common.del_vip_fw_rule(
|
||||||
|
self.vcns, binding['edge_id'],
|
||||||
binding['edge_fw_rule_id'])
|
binding['edge_fw_rule_id'])
|
||||||
except nsxv_exc.VcnsApiException as e:
|
except nsxv_exc.VcnsApiException as e:
|
||||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s FW rule. '
|
LOG.error(_LE('Failed to delete loadbalancer %(lb)s '
|
||||||
'exception is %(exc)s'), {'lb': lb.id, 'exc': e})
|
'FW rule. exception is %(exc)s'),
|
||||||
|
{'lb': lb.id, 'exc': e})
|
||||||
try:
|
try:
|
||||||
lb_common.del_vip_as_secondary_ip(self.vcns,
|
lb_common.del_vip_as_secondary_ip(self.vcns,
|
||||||
binding['edge_id'],
|
binding['edge_id'],
|
||||||
lb.vip_address)
|
lb.vip_address)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s interface'
|
LOG.error(_LE('Failed to delete loadbalancer %(lb)s '
|
||||||
' IP. exception is %(exc)s'),
|
'interface IP. exception is %(exc)s'),
|
||||||
{'lb': lb.id, 'exc': e})
|
{'lb': lb.id, 'exc': e})
|
||||||
|
|
||||||
nsxv_db.del_nsxv_lbaas_loadbalancer_binding(context.session, lb.id)
|
nsxv_db.del_nsxv_lbaas_loadbalancer_binding(context.session, lb.id)
|
||||||
@ -104,3 +132,25 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
'total_connections': 0}
|
'total_connections': 0}
|
||||||
|
|
||||||
return stats
|
return stats
|
||||||
|
|
||||||
|
def _handle_subnet_gw_change(self, *args, **kwargs):
|
||||||
|
# As the Edge appliance doesn't use DHCP, we should change the
|
||||||
|
# default gateway here when the subnet GW changes.
|
||||||
|
context = kwargs.get('context')
|
||||||
|
subnet_id = kwargs.get('subnet_id')
|
||||||
|
subnet = self.core_plugin.get_subnet(context.elevated(), subnet_id)
|
||||||
|
|
||||||
|
filters = {'fixed_ips': {'subnet_id': [subnet_id]},
|
||||||
|
'device_owner': [constants.DEVICE_OWNER_LOADBALANCERV2]}
|
||||||
|
lb_ports = self.core_plugin.get_ports(context.elevated(),
|
||||||
|
filters=filters)
|
||||||
|
|
||||||
|
if lb_ports:
|
||||||
|
for lb_port in lb_ports:
|
||||||
|
if lb_port['device_id']:
|
||||||
|
edge_bind = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
||||||
|
context.session, lb_port['device_id'])
|
||||||
|
edge_id = edge_bind['edge_id']
|
||||||
|
|
||||||
|
self.core_plugin.nsx_v.update_routes(
|
||||||
|
edge_id, subnet['gateway_ip'], [])
|
||||||
|
@ -132,10 +132,8 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
|||||||
return 'load_balancer'
|
return 'load_balancer'
|
||||||
|
|
||||||
def test_create(self):
|
def test_create(self):
|
||||||
with mock.patch.object(lb_common, 'get_lbaas_edge_id_for_subnet'
|
with mock.patch.object(lb_common, 'get_lbaas_edge_id'
|
||||||
) as mock_get_edge, \
|
) as mock_get_edge, \
|
||||||
mock.patch.object(lb_common, 'add_vip_as_secondary_ip'
|
|
||||||
) as mock_vip_sec_ip, \
|
|
||||||
mock.patch.object(lb_common, 'add_vip_fw_rule'
|
mock.patch.object(lb_common, 'add_vip_fw_rule'
|
||||||
) as mock_add_vip_fwr, \
|
) as mock_add_vip_fwr, \
|
||||||
mock.patch.object(lb_common, 'enable_edge_acceleration'
|
mock.patch.object(lb_common, 'enable_edge_acceleration'
|
||||||
@ -151,9 +149,6 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
|||||||
|
|
||||||
self.edge_driver.loadbalancer.create(self.context, self.lb)
|
self.edge_driver.loadbalancer.create(self.context, self.lb)
|
||||||
|
|
||||||
mock_vip_sec_ip.assert_called_with(self.edge_driver.vcns,
|
|
||||||
LB_EDGE_ID,
|
|
||||||
LB_VIP)
|
|
||||||
mock_add_vip_fwr.assert_called_with(self.edge_driver.vcns,
|
mock_add_vip_fwr.assert_called_with(self.edge_driver.vcns,
|
||||||
LB_EDGE_ID,
|
LB_EDGE_ID,
|
||||||
LB_ID,
|
LB_ID,
|
||||||
@ -187,9 +182,14 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
|||||||
mock.patch.object(lb_common, 'del_vip_as_secondary_ip'
|
mock.patch.object(lb_common, 'del_vip_as_secondary_ip'
|
||||||
) as mock_vip_sec_ip, \
|
) as mock_vip_sec_ip, \
|
||||||
mock.patch.object(nsxv_db, 'del_nsxv_lbaas_loadbalancer_binding',
|
mock.patch.object(nsxv_db, 'del_nsxv_lbaas_loadbalancer_binding',
|
||||||
) as mock_del_binding:
|
) as mock_del_binding, \
|
||||||
|
mock.patch.object(self.core_plugin, 'get_ports'
|
||||||
|
) as mock_get_ports, \
|
||||||
|
mock.patch.object(nsxv_db, 'get_nsxv_router_binding_by_edge'
|
||||||
|
) as mock_get_r_binding:
|
||||||
mock_get_binding.return_value = LB_BINDING
|
mock_get_binding.return_value = LB_BINDING
|
||||||
|
mock_get_ports.return_value = []
|
||||||
|
mock_get_r_binding.return_value = {'router_id': 'xxxx'}
|
||||||
self.edge_driver.loadbalancer.delete(self.context, self.lb)
|
self.edge_driver.loadbalancer.delete(self.context, self.lb)
|
||||||
|
|
||||||
mock_del_fwr.assert_called_with(self.edge_driver.vcns,
|
mock_del_fwr.assert_called_with(self.edge_driver.vcns,
|
||||||
|
Loading…
Reference in New Issue
Block a user