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']
|
||||
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):
|
||||
lb_id = self._get_pool_lb_id(member)
|
||||
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)
|
||||
|
||||
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):
|
||||
if (not cfg.CONF.nsxv.use_routers_as_lbaas_platform and
|
||||
not lb_common.is_lb_on_router_edge(context.elevated(),
|
||||
self.core_plugin,
|
||||
edge_id)):
|
||||
if not cfg.CONF.nsxv.use_routers_as_lbaas_platform and not old_lb:
|
||||
# Verify that Edge appliance is connected to the member's
|
||||
# subnet (only if this is a dedicated loadbalancer edge)
|
||||
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)
|
||||
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:
|
||||
with excutils.save_and_reraise_exception():
|
||||
completor(success=False)
|
||||
@ -150,6 +172,9 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
context.session, lb_id, member['pool_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):
|
||||
if not cfg.CONF.nsxv.use_routers_as_lbaas_platform:
|
||||
# we should remove LB subnet interface if no members are
|
||||
@ -182,6 +207,16 @@ class EdgeMemberManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
except nsxv_exc.VcnsApiException:
|
||||
|
@ -34,6 +34,7 @@ class EdgePoolManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
@log_helpers.log_method_call
|
||||
def __init__(self, vcns_driver):
|
||||
super(EdgePoolManagerFromDict, self).__init__(vcns_driver)
|
||||
self._fw_section_id = None
|
||||
|
||||
def create(self, context, pool, completor):
|
||||
|
||||
@ -191,6 +192,20 @@ class EdgePoolManagerFromDict(base_mgr.EdgeLoadbalancerBaseManager):
|
||||
listener_mgr.update_app_profile(
|
||||
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:
|
||||
completor(success=False)
|
||||
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
|
||||
# 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 exceptions as n_exc
|
||||
from oslo_log import log as logging
|
||||
|
||||
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
|
||||
from vmware_nsx.plugins.nsx_v.vshield import vcns as nsxv_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
MEMBER_ID_PFX = 'member-'
|
||||
RESOURCE_ID_PFX = 'lbaas-'
|
||||
LBAAS_FW_SECTION_NAME = 'LBaaS FW Rules'
|
||||
|
||||
|
||||
def get_member_id(member_id):
|
||||
@ -300,6 +303,64 @@ def get_edge_ip_addresses(vcns, edge_id):
|
||||
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):
|
||||
with locking.LockManager.get_lock(edge_id):
|
||||
# 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]),
|
||||
constants.BGP_NEIGHBOUR: Resource(constants.BGP_NEIGHBOUR,
|
||||
[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, \
|
||||
mock.patch.object(nsxv_db, 'del_nsxv_lbaas_pool_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_get_lb_binding.return_value = LB_BINDING
|
||||
mock_get_pool_binding.return_value = POOL_BINDING
|
||||
mock_get_listener_binding.return_value = LISTENER_BINDING
|
||||
mock_lb_router.return_value = False
|
||||
|
||||
self.edge_driver.pool.delete(self.context, self.pool)
|
||||
|
||||
@ -709,12 +712,15 @@ class TestEdgeLbaasV2Member(BaseTestEdgeLbaasV2):
|
||||
) as mock_get_pool, \
|
||||
mock.patch.object(self.core_plugin, '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'
|
||||
) as mock_del_lb_iface, \
|
||||
mock.patch.object(self.edge_driver.vcns, 'update_pool'
|
||||
) as mock_update_pool:
|
||||
mock_get_lb_binding.return_value = LB_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['member'] = [EDGE_MEMBER_DEF]
|
||||
mock_get_pool.return_value = (None, edge_pool_def)
|
||||
|
Loading…
Reference in New Issue
Block a user