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-'
|
||||
PLR_EDGE_PREFIX = 'plr-'
|
||||
BACKUP_ROUTER_PREFIX = 'backup-'
|
||||
LB_EDGE_PREFIX = 'lb-'
|
||||
EDGE_NAME_LEN = 20
|
||||
|
||||
# Interface
|
||||
@ -59,7 +60,8 @@ SUFFIX_LENGTH = 8
|
||||
#Edge size
|
||||
SERVICE_SIZE_MAPPING = {
|
||||
'router': nsxv_constants.COMPACT,
|
||||
'dhcp': nsxv_constants.COMPACT
|
||||
'dhcp': nsxv_constants.COMPACT,
|
||||
'lb': nsxv_constants.COMPACT
|
||||
}
|
||||
ALLOWED_EDGE_SIZES = (nsxv_constants.COMPACT,
|
||||
nsxv_constants.LARGE,
|
||||
|
@ -814,6 +814,15 @@ class EdgeManager(object):
|
||||
appliance_size=vcns_const.SERVICE_SIZE_MAPPING['dhcp'],
|
||||
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):
|
||||
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
|
||||
@ -855,6 +864,8 @@ class EdgeManager(object):
|
||||
self.update_syslog_by_flavor(context,
|
||||
lrouter['id'], lrouter['flavor_id'], edge_id)
|
||||
|
||||
return edge_id
|
||||
|
||||
def delete_lrouter(self, context, router_id, dist=False):
|
||||
self._free_edge_appliance(context, router_id)
|
||||
|
||||
|
@ -15,11 +15,12 @@
|
||||
|
||||
import netaddr
|
||||
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import exceptions as n_exc
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
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-'
|
||||
|
||||
@ -28,25 +29,49 @@ def get_member_id(member_id):
|
||||
return MEMBER_ID_PFX + member_id
|
||||
|
||||
|
||||
def get_lbaas_edge_id_for_subnet(context, plugin, subnet_id, tenant_id):
|
||||
"""
|
||||
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'])
|
||||
def get_lb_resource_id(lb_id):
|
||||
return ('lbaas-' + lb_id)[:36]
|
||||
|
||||
for attached_router in attached_routers:
|
||||
router = plugin.get_router(context, attached_router['device_id'])
|
||||
if router.get('router_type') == 'exclusive':
|
||||
rtr_bindings = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
router['id'])
|
||||
return rtr_bindings['edge_id']
|
||||
|
||||
def get_lbaas_edge_id(context, plugin, lb_id, vip_addr, subnet_id, tenant_id):
|
||||
subnet = plugin.get_subnet(context, subnet_id)
|
||||
network_id = subnet.get('network_id')
|
||||
availability_zone = plugin.get_network_az(context, network_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):
|
||||
|
@ -13,6 +13,10 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# 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 oslo_log import helpers as log_helpers
|
||||
from oslo_log import log as logging
|
||||
@ -31,15 +35,20 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
@log_helpers.log_method_call
|
||||
def __init__(self, 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
|
||||
def create(self, context, lb):
|
||||
edge_id = lb_common.get_lbaas_edge_id_for_subnet(
|
||||
context, self.core_plugin, lb.vip_subnet_id, lb.tenant_id)
|
||||
edge_id = lb_common.get_lbaas_edge_id(
|
||||
context, self.core_plugin, lb.id, lb.vip_address, lb.vip_subnet_id,
|
||||
lb.tenant_id)
|
||||
|
||||
if not edge_id:
|
||||
msg = _(
|
||||
'No suitable Edge found for subnet %s') % lb.vip_subnet_id
|
||||
msg = _('Failed to allocate Edge on subnet %(sub)s for '
|
||||
'loadbalancer %(lb)s') % {'sub': lb.vip_subnet_id,
|
||||
'lb': lb.id}
|
||||
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
||||
|
||||
try:
|
||||
@ -47,8 +56,6 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
context.session, 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(
|
||||
self.vcns, edge_id, lb.id, lb.vip_address)
|
||||
|
||||
@ -68,22 +75,43 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
|
||||
@log_helpers.log_method_call
|
||||
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(
|
||||
context.session, lb.id)
|
||||
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:
|
||||
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'])
|
||||
except nsxv_exc.VcnsApiException as e:
|
||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s FW rule. '
|
||||
'exception is %(exc)s'), {'lb': lb.id, 'exc': e})
|
||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s '
|
||||
'FW rule. exception is %(exc)s'),
|
||||
{'lb': lb.id, 'exc': e})
|
||||
try:
|
||||
lb_common.del_vip_as_secondary_ip(self.vcns,
|
||||
binding['edge_id'],
|
||||
lb.vip_address)
|
||||
except Exception as e:
|
||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s interface'
|
||||
' IP. exception is %(exc)s'),
|
||||
LOG.error(_LE('Failed to delete loadbalancer %(lb)s '
|
||||
'interface IP. exception is %(exc)s'),
|
||||
{'lb': lb.id, 'exc': e})
|
||||
|
||||
nsxv_db.del_nsxv_lbaas_loadbalancer_binding(context.session, lb.id)
|
||||
@ -104,3 +132,25 @@ class EdgeLoadBalancerManager(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
'total_connections': 0}
|
||||
|
||||
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'
|
||||
|
||||
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, \
|
||||
mock.patch.object(lb_common, 'add_vip_as_secondary_ip'
|
||||
) as mock_vip_sec_ip, \
|
||||
mock.patch.object(lb_common, 'add_vip_fw_rule'
|
||||
) as mock_add_vip_fwr, \
|
||||
mock.patch.object(lb_common, 'enable_edge_acceleration'
|
||||
@ -151,9 +149,6 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
||||
|
||||
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,
|
||||
LB_EDGE_ID,
|
||||
LB_ID,
|
||||
@ -187,9 +182,14 @@ class TestEdgeLbaasV2Loadbalancer(BaseTestEdgeLbaasV2):
|
||||
mock.patch.object(lb_common, 'del_vip_as_secondary_ip'
|
||||
) as mock_vip_sec_ip, \
|
||||
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_ports.return_value = []
|
||||
mock_get_r_binding.return_value = {'router_id': 'xxxx'}
|
||||
self.edge_driver.loadbalancer.delete(self.context, self.lb)
|
||||
|
||||
mock_del_fwr.assert_called_with(self.edge_driver.vcns,
|
||||
|
Loading…
Reference in New Issue
Block a user