Merge "LBaaS legacy mode bugfix"
This commit is contained in:
commit
b91995ab0f
@ -45,6 +45,19 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
lb_id = member['pool']['loadbalancer']['id']
|
lb_id = member['pool']['loadbalancer']['id']
|
||||||
return lb_id
|
return lb_id
|
||||||
|
|
||||||
|
def _get_pool_member_ips(self, pool, operation, address):
|
||||||
|
member_ips = [member['address'] for member in pool['members']]
|
||||||
|
if operation == 'add' and address not in member_ips:
|
||||||
|
member_ips.append(address)
|
||||||
|
elif operation == 'del' and address in member_ips:
|
||||||
|
member_ips.remove(address)
|
||||||
|
return member_ips
|
||||||
|
|
||||||
|
def _get_lbaas_fw_section_id(self):
|
||||||
|
if not self._fw_section_id:
|
||||||
|
self._fw_section_id = lb_common.get_lbaas_fw_section_id(self.vcns)
|
||||||
|
return self._fw_section_id
|
||||||
|
|
||||||
def create(self, context, member, completor):
|
def create(self, context, member, completor):
|
||||||
lb_id = self._get_pool_lb_id(member)
|
lb_id = self._get_pool_lb_id(member)
|
||||||
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
||||||
@ -61,11 +74,10 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
||||||
|
|
||||||
edge_pool_id = pool_binding['edge_pool_id']
|
edge_pool_id = pool_binding['edge_pool_id']
|
||||||
|
old_lb = lb_common.is_lb_on_router_edge(
|
||||||
|
context, self.core_plugin, edge_id)
|
||||||
with locking.LockManager.get_lock(edge_id):
|
with locking.LockManager.get_lock(edge_id):
|
||||||
if (not cfg.CONF.nsxv.use_routers_as_lbaas_platform and
|
if not cfg.CONF.nsxv.use_routers_as_lbaas_platform and not old_lb:
|
||||||
not lb_common.is_lb_on_router_edge(context.elevated(),
|
|
||||||
self.core_plugin,
|
|
||||||
edge_id)):
|
|
||||||
# Verify that Edge appliance is connected to the member's
|
# Verify that Edge appliance is connected to the member's
|
||||||
# subnet (only if this is a dedicated loadbalancer edge)
|
# subnet (only if this is a dedicated loadbalancer edge)
|
||||||
if not lb_common.get_lb_interface(
|
if not lb_common.get_lb_interface(
|
||||||
@ -93,6 +105,16 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
self.vcns.update_pool(edge_id, edge_pool_id, edge_pool)
|
self.vcns.update_pool(edge_id, edge_pool_id, edge_pool)
|
||||||
completor(success=True)
|
completor(success=True)
|
||||||
|
|
||||||
|
if old_lb:
|
||||||
|
member_ips = self._get_pool_member_ips(member['pool'],
|
||||||
|
'add',
|
||||||
|
member['address'])
|
||||||
|
lb_common.update_pool_fw_rule(
|
||||||
|
self.vcns, member['pool_id'],
|
||||||
|
edge_id,
|
||||||
|
self._get_lbaas_fw_section_id(),
|
||||||
|
member_ips)
|
||||||
|
|
||||||
except nsxv_exc.VcnsApiException:
|
except nsxv_exc.VcnsApiException:
|
||||||
with excutils.save_and_reraise_exception():
|
with excutils.save_and_reraise_exception():
|
||||||
completor(success=False)
|
completor(success=False)
|
||||||
@ -150,6 +172,9 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
context.session, lb_id, member['pool_id'])
|
context.session, lb_id, member['pool_id'])
|
||||||
edge_id = lb_binding['edge_id']
|
edge_id = lb_binding['edge_id']
|
||||||
|
|
||||||
|
old_lb = lb_common.is_lb_on_router_edge(
|
||||||
|
context, self.core_plugin, edge_id)
|
||||||
|
|
||||||
with locking.LockManager.get_lock(edge_id):
|
with locking.LockManager.get_lock(edge_id):
|
||||||
if not cfg.CONF.nsxv.use_routers_as_lbaas_platform:
|
if not cfg.CONF.nsxv.use_routers_as_lbaas_platform:
|
||||||
# we should remove LB subnet interface if no members are
|
# we should remove LB subnet interface if no members are
|
||||||
@ -182,6 +207,16 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
self.vcns.update_pool(edge_id, edge_pool_id, edge_pool)
|
self.vcns.update_pool(edge_id, edge_pool_id, edge_pool)
|
||||||
|
if old_lb:
|
||||||
|
member_ips = self._get_pool_member_ips(member['pool'],
|
||||||
|
'del',
|
||||||
|
member['address'])
|
||||||
|
lb_common.update_pool_fw_rule(
|
||||||
|
self.vcns, member['pool_id'],
|
||||||
|
edge_id,
|
||||||
|
self._get_lbaas_fw_section_id(),
|
||||||
|
member_ips)
|
||||||
|
|
||||||
completor(success=True)
|
completor(success=True)
|
||||||
|
|
||||||
except nsxv_exc.VcnsApiException:
|
except nsxv_exc.VcnsApiException:
|
||||||
|
@ -34,6 +34,7 @@ class EdgePoolManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
@log_helpers.log_method_call
|
@log_helpers.log_method_call
|
||||||
def __init__(self, vcns_driver):
|
def __init__(self, vcns_driver):
|
||||||
super(EdgePoolManagerFromDict, self).__init__(vcns_driver)
|
super(EdgePoolManagerFromDict, self).__init__(vcns_driver)
|
||||||
|
self._fw_section_id = None
|
||||||
|
|
||||||
def create(self, context, pool, completor):
|
def create(self, context, pool, completor):
|
||||||
|
|
||||||
@ -191,6 +192,20 @@ class EdgePoolManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
|||||||
listener_mgr.update_app_profile(
|
listener_mgr.update_app_profile(
|
||||||
self.vcns, context, listener, edge_id)
|
self.vcns, context, listener, edge_id)
|
||||||
|
|
||||||
|
old_lb = lb_common.is_lb_on_router_edge(
|
||||||
|
context, self.core_plugin, lb_binding['edge_id'])
|
||||||
|
|
||||||
|
if old_lb:
|
||||||
|
lb_common.update_pool_fw_rule(self.vcns, pool['id'],
|
||||||
|
edge_id,
|
||||||
|
self._get_lbaas_fw_section_id(),
|
||||||
|
[])
|
||||||
|
|
||||||
except nsxv_exc.VcnsApiException:
|
except nsxv_exc.VcnsApiException:
|
||||||
completor(success=False)
|
completor(success=False)
|
||||||
LOG.error('Failed to delete pool %s', pool['id'])
|
LOG.error('Failed to delete pool %s', pool['id'])
|
||||||
|
|
||||||
|
def _get_lbaas_fw_section_id(self):
|
||||||
|
if not self._fw_section_id:
|
||||||
|
self._fw_section_id = lb_common.get_lbaas_fw_section_id(self.vcns)
|
||||||
|
return self._fw_section_id
|
||||||
|
@ -13,22 +13,25 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import netaddr
|
import xml.etree.ElementTree as et
|
||||||
|
|
||||||
from oslo_log import log as logging
|
import netaddr
|
||||||
|
|
||||||
from neutron_lib import constants
|
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 log as logging
|
||||||
|
|
||||||
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.db import nsxv_db
|
||||||
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
|
from vmware_nsx.plugins.nsx_v.vshield import edge_utils
|
||||||
|
from vmware_nsx.plugins.nsx_v.vshield import vcns as nsxv_api
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MEMBER_ID_PFX = 'member-'
|
MEMBER_ID_PFX = 'member-'
|
||||||
RESOURCE_ID_PFX = 'lbaas-'
|
RESOURCE_ID_PFX = 'lbaas-'
|
||||||
|
LBAAS_FW_SECTION_NAME = 'LBaaS FW Rules'
|
||||||
|
|
||||||
|
|
||||||
def get_member_id(member_id):
|
def get_member_id(member_id):
|
||||||
@ -300,6 +303,64 @@ def get_edge_ip_addresses(vcns, edge_id):
|
|||||||
return edge_ips
|
return edge_ips
|
||||||
|
|
||||||
|
|
||||||
|
def update_pool_fw_rule(vcns, pool_id, edge_id, section_id, member_ips):
|
||||||
|
edge_ips = get_edge_ip_addresses(vcns, edge_id)
|
||||||
|
|
||||||
|
with locking.LockManager.get_lock('lbaas-fw-section'):
|
||||||
|
section_uri = '%s/%s/%s' % (nsxv_api.FIREWALL_PREFIX,
|
||||||
|
'layer3sections',
|
||||||
|
section_id)
|
||||||
|
xml_section = vcns.get_section(section_uri)[1]
|
||||||
|
section = et.fromstring(xml_section)
|
||||||
|
pool_rule = None
|
||||||
|
for rule in section.iter('rule'):
|
||||||
|
if rule.find('name').text == pool_id:
|
||||||
|
pool_rule = rule
|
||||||
|
if member_ips:
|
||||||
|
pool_rule.find('sources').find('source').find(
|
||||||
|
'value').text = (','.join(edge_ips))
|
||||||
|
pool_rule.find('destinations').find(
|
||||||
|
'destination').find('value').text = ','.join(
|
||||||
|
member_ips)
|
||||||
|
else:
|
||||||
|
section.remove(pool_rule)
|
||||||
|
break
|
||||||
|
|
||||||
|
if member_ips and pool_rule is None:
|
||||||
|
pool_rule = et.SubElement(section, 'rule')
|
||||||
|
et.SubElement(pool_rule, 'name').text = pool_id
|
||||||
|
et.SubElement(pool_rule, 'action').text = 'allow'
|
||||||
|
sources = et.SubElement(pool_rule, 'sources')
|
||||||
|
sources.attrib['excluded'] = 'false'
|
||||||
|
source = et.SubElement(sources, 'source')
|
||||||
|
et.SubElement(source, 'type').text = 'Ipv4Address'
|
||||||
|
et.SubElement(source, 'value').text = ','.join(edge_ips)
|
||||||
|
|
||||||
|
destinations = et.SubElement(pool_rule, 'destinations')
|
||||||
|
destinations.attrib['excluded'] = 'false'
|
||||||
|
destination = et.SubElement(destinations, 'destination')
|
||||||
|
et.SubElement(destination, 'type').text = 'Ipv4Address'
|
||||||
|
et.SubElement(destination, 'value').text = ','.join(member_ips)
|
||||||
|
|
||||||
|
vcns.update_section(section_uri,
|
||||||
|
et.tostring(section, encoding="us-ascii"),
|
||||||
|
None)
|
||||||
|
|
||||||
|
|
||||||
|
def get_lbaas_fw_section_id(vcns):
|
||||||
|
# Avoid concurrent creation of section by multiple neutron
|
||||||
|
# instances
|
||||||
|
with locking.LockManager.get_lock('lbaas-fw-section'):
|
||||||
|
fw_section_id = vcns.get_section_id(LBAAS_FW_SECTION_NAME)
|
||||||
|
if not fw_section_id:
|
||||||
|
section = et.Element('section')
|
||||||
|
section.attrib['name'] = LBAAS_FW_SECTION_NAME
|
||||||
|
sect = vcns.create_section('ip', et.tostring(section))[1]
|
||||||
|
fw_section_id = et.fromstring(sect).attrib['id']
|
||||||
|
|
||||||
|
return fw_section_id
|
||||||
|
|
||||||
|
|
||||||
def enable_edge_acceleration(vcns, edge_id):
|
def enable_edge_acceleration(vcns, edge_id):
|
||||||
with locking.LockManager.get_lock(edge_id):
|
with locking.LockManager.get_lock(edge_id):
|
||||||
# Query the existing load balancer config in case metadata lb is set
|
# Query the existing load balancer config in case metadata lb is set
|
||||||
|
80
vmware_nsx/shell/admin/plugins/nsxv/resources/lbaas.py
Normal file
80
vmware_nsx/shell/admin/plugins/nsxv/resources/lbaas.py
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
# Copyright 2018 VMware, Inc.
|
||||||
|
# All Rights Reserved
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import xml.etree.ElementTree as et
|
||||||
|
|
||||||
|
from neutron_lbaas.db.loadbalancer import models as nlbaas_v2
|
||||||
|
from neutron_lib.callbacks import registry
|
||||||
|
|
||||||
|
from vmware_nsx.common import locking
|
||||||
|
from vmware_nsx.plugins.nsx_v.vshield import vcns as nsxv_api
|
||||||
|
from vmware_nsx.shell.admin.plugins.common import constants
|
||||||
|
from vmware_nsx.shell.admin.plugins.common.utils import output_header
|
||||||
|
from vmware_nsx.shell.admin.plugins.nsxv.resources import utils as utils
|
||||||
|
from vmware_nsx.shell.resources import Operations
|
||||||
|
|
||||||
|
LBAAS_FW_SECTION_NAME = 'LBaaS FW Rules'
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@output_header
|
||||||
|
def sync_lbaas_dfw_rules(resource, event, trigger, **kwargs):
|
||||||
|
vcns = utils.get_nsxv_client()
|
||||||
|
with locking.LockManager.get_lock('lbaas-fw-section'):
|
||||||
|
fw_section_id = vcns.get_section_id(LBAAS_FW_SECTION_NAME)
|
||||||
|
if not fw_section_id:
|
||||||
|
section = et.Element('section')
|
||||||
|
section.attrib['name'] = LBAAS_FW_SECTION_NAME
|
||||||
|
sect = vcns.create_section('ip', et.tostring(section))[1]
|
||||||
|
fw_section_id = et.fromstring(sect).attrib['id']
|
||||||
|
|
||||||
|
if not fw_section_id:
|
||||||
|
LOG.error('No LBaaS FW Section id found')
|
||||||
|
return
|
||||||
|
|
||||||
|
neutron_db = utils.NeutronDbClient()
|
||||||
|
pools = neutron_db.context.session.query(nlbaas_v2.PoolV2).all()
|
||||||
|
pool_ids = [pool['id'] for pool in pools]
|
||||||
|
|
||||||
|
section_uri = '%s/%s/%s' % (nsxv_api.FIREWALL_PREFIX,
|
||||||
|
'layer3sections',
|
||||||
|
fw_section_id)
|
||||||
|
|
||||||
|
xml_section_data = vcns.get_section(section_uri)
|
||||||
|
if xml_section_data:
|
||||||
|
xml_section = xml_section_data[1]
|
||||||
|
else:
|
||||||
|
LOG.info('LBaaS XML section was not found!')
|
||||||
|
return
|
||||||
|
|
||||||
|
section = et.fromstring(xml_section)
|
||||||
|
|
||||||
|
for rule in section.findall('.//rule'):
|
||||||
|
if rule.find('name').text in pool_ids:
|
||||||
|
LOG.info('Rule %s found and valid', rule.find('name').text)
|
||||||
|
else:
|
||||||
|
section.remove(rule)
|
||||||
|
LOG.info('Rule %s is stale and removed',
|
||||||
|
rule.find('name').text)
|
||||||
|
|
||||||
|
vcns.update_section(section_uri,
|
||||||
|
et.tostring(section, encoding="us-ascii"),
|
||||||
|
None)
|
||||||
|
|
||||||
|
|
||||||
|
registry.subscribe(sync_lbaas_dfw_rules,
|
||||||
|
constants.LBAAS,
|
||||||
|
Operations.NSX_UPDATE.value)
|
@ -215,7 +215,9 @@ nsxv_resources = {
|
|||||||
Operations.DELETE.value]),
|
Operations.DELETE.value]),
|
||||||
constants.BGP_NEIGHBOUR: Resource(constants.BGP_NEIGHBOUR,
|
constants.BGP_NEIGHBOUR: Resource(constants.BGP_NEIGHBOUR,
|
||||||
[Operations.CREATE.value,
|
[Operations.CREATE.value,
|
||||||
Operations.DELETE.value])
|
Operations.DELETE.value]),
|
||||||
|
constants.LBAAS: Resource(constants.LBAAS,
|
||||||
|
[Operations.NSX_UPDATE.value]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -611,11 +611,14 @@ class TestEdgeLbaasV2Pool(BaseTestEdgeLbaasV2):
|
|||||||
) as mock_del_pool, \
|
) as mock_del_pool, \
|
||||||
mock.patch.object(nsxv_db, 'del_nsxv_lbaas_pool_binding'
|
mock.patch.object(nsxv_db, 'del_nsxv_lbaas_pool_binding'
|
||||||
) as mock_del_binding,\
|
) as mock_del_binding,\
|
||||||
|
mock.patch.object(lb_common, 'is_lb_on_router_edge'
|
||||||
|
) as mock_lb_router, \
|
||||||
mock.patch.object(self.edge_driver.vcns, 'update_app_profile'
|
mock.patch.object(self.edge_driver.vcns, 'update_app_profile'
|
||||||
):
|
):
|
||||||
mock_get_lb_binding.return_value = LB_BINDING
|
mock_get_lb_binding.return_value = LB_BINDING
|
||||||
mock_get_pool_binding.return_value = POOL_BINDING
|
mock_get_pool_binding.return_value = POOL_BINDING
|
||||||
mock_get_listener_binding.return_value = LISTENER_BINDING
|
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||||
|
mock_lb_router.return_value = False
|
||||||
|
|
||||||
self.edge_driver.pool.delete(self.context, self.pool)
|
self.edge_driver.pool.delete(self.context, self.pool)
|
||||||
|
|
||||||
@ -709,12 +712,15 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
|
|||||||
) as mock_get_pool, \
|
) as mock_get_pool, \
|
||||||
mock.patch.object(self.core_plugin, 'get_ports'
|
mock.patch.object(self.core_plugin, 'get_ports'
|
||||||
) as mock_get_ports, \
|
) as mock_get_ports, \
|
||||||
|
mock.patch.object(lb_common, 'is_lb_on_router_edge'
|
||||||
|
) as mock_lb_router, \
|
||||||
mock.patch.object(lb_common, 'delete_lb_interface'
|
mock.patch.object(lb_common, 'delete_lb_interface'
|
||||||
) as mock_del_lb_iface, \
|
) as mock_del_lb_iface, \
|
||||||
mock.patch.object(self.edge_driver.vcns, 'update_pool'
|
mock.patch.object(self.edge_driver.vcns, 'update_pool'
|
||||||
) as mock_update_pool:
|
) as mock_update_pool:
|
||||||
mock_get_lb_binding.return_value = LB_BINDING
|
mock_get_lb_binding.return_value = LB_BINDING
|
||||||
mock_get_pool_binding.return_value = POOL_BINDING
|
mock_get_pool_binding.return_value = POOL_BINDING
|
||||||
|
mock_lb_router.return_value = False
|
||||||
edge_pool_def = EDGE_POOL_DEF.copy()
|
edge_pool_def = EDGE_POOL_DEF.copy()
|
||||||
edge_pool_def['member'] = [EDGE_MEMBER_DEF]
|
edge_pool_def['member'] = [EDGE_MEMBER_DEF]
|
||||||
mock_get_pool.return_value = (None, edge_pool_def)
|
mock_get_pool.return_value = (None, edge_pool_def)
|
||||||
|
Loading…
Reference in New Issue
Block a user