60f212fba8
In case a loadbalancer was alrady deleted from neutron & nsx but not
from octavia, delete cascade fails to find binding entries.
Fixing that and also adding some logs in the delete cascade logic to make
debugging easier.
Change-Id: Id385366436eda75ad07dc073c5027791efb4d3d9
(cherry picked from commit 1745835153
)
229 lines
9.5 KiB
Python
229 lines
9.5 KiB
Python
# Copyright 2015 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.
|
|
|
|
from oslo_config import cfg
|
|
from oslo_log import helpers as log_helpers
|
|
from oslo_log import log as logging
|
|
from oslo_utils import excutils
|
|
|
|
from neutron_lib import exceptions as n_exc
|
|
|
|
from vmware_nsx.common import locking
|
|
from vmware_nsx.db import nsxv_db
|
|
from vmware_nsx.plugins.nsx_v.vshield.common import exceptions as nsxv_exc
|
|
from vmware_nsx.services.lbaas import base_mgr
|
|
from vmware_nsx.services.lbaas import lb_const
|
|
from vmware_nsx.services.lbaas.nsx_v.implementation import listener_mgr
|
|
from vmware_nsx.services.lbaas.nsx_v import lbaas_common as lb_common
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
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
|
|
self.pool_transparency = (
|
|
cfg.CONF.nsxv.use_routers_as_lbaas_platform and
|
|
cfg.CONF.nsxv.loadbalancer_pool_transparency)
|
|
|
|
def create(self, context, pool, completor):
|
|
|
|
pool_id = pool['id']
|
|
edge_pool = {
|
|
'name': 'pool_' + pool_id,
|
|
'description': pool.get('description', pool.get('name')),
|
|
'algorithm': lb_const.BALANCE_MAP.get(pool['lb_algorithm'],
|
|
'round-robin'),
|
|
'transparent': self.pool_transparency
|
|
}
|
|
|
|
lb_id = pool['loadbalancer_id']
|
|
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
|
context.session, lb_id)
|
|
if not lb_binding:
|
|
msg = _(
|
|
'No suitable Edge found for pool %s') % pool_id
|
|
raise n_exc.BadRequest(resource='edge-lbaas', msg=msg)
|
|
edge_id = lb_binding['edge_id']
|
|
|
|
try:
|
|
with locking.LockManager.get_lock(edge_id):
|
|
h = self.vcns.create_pool(edge_id, edge_pool)[0]
|
|
edge_pool_id = lb_common.extract_resource_id(h['location'])
|
|
nsxv_db.add_nsxv_lbaas_pool_binding(context.session, lb_id,
|
|
pool_id,
|
|
edge_pool_id)
|
|
|
|
if pool['listener']:
|
|
listener_binding = nsxv_db.get_nsxv_lbaas_listener_binding(
|
|
context.session, lb_id, pool['listener']['id'])
|
|
# Associate listener with pool
|
|
vse = listener_mgr.listener_to_edge_vse(
|
|
context,
|
|
pool['listener'],
|
|
lb_binding['vip_address'],
|
|
edge_pool_id,
|
|
listener_binding['app_profile_id'])
|
|
with locking.LockManager.get_lock(edge_id):
|
|
self.vcns.update_vip(edge_id, listener_binding['vse_id'],
|
|
vse)
|
|
# This action also set this pool as the default pool of the
|
|
# listener, so the application profile may need to be updated
|
|
if pool['session_persistence']:
|
|
if not pool['listener'].get('default_pool'):
|
|
pool['listener']['default_pool'] = pool
|
|
listener_mgr.update_app_profile(
|
|
self.vcns, context, pool['listener'], edge_id)
|
|
|
|
completor(success=True)
|
|
|
|
except nsxv_exc.VcnsApiException:
|
|
with excutils.save_and_reraise_exception():
|
|
completor(success=False)
|
|
LOG.error('Failed to create pool %s', pool['id'])
|
|
|
|
def update(self, context, old_pool, new_pool, completor):
|
|
edge_pool = {
|
|
'name': 'pool_' + new_pool['id'],
|
|
'description': new_pool.get('description', new_pool.get('name')),
|
|
'algorithm': lb_const.BALANCE_MAP.get(
|
|
new_pool['lb_algorithm'], 'round-robin'),
|
|
'transparent': False
|
|
}
|
|
|
|
if new_pool['listener']:
|
|
listener = new_pool['listener']
|
|
lb_id = listener['loadbalancer_id']
|
|
else:
|
|
lb_id = new_pool['loadbalancer_id']
|
|
|
|
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
|
context.session, lb_id)
|
|
pool_binding = nsxv_db.get_nsxv_lbaas_pool_binding(
|
|
context.session, lb_id, new_pool['id'])
|
|
|
|
edge_id = lb_binding['edge_id']
|
|
edge_pool_id = pool_binding['edge_pool_id']
|
|
|
|
try:
|
|
with locking.LockManager.get_lock(edge_id):
|
|
# get the configured monitor-id
|
|
org_edge_pool = self.vcns.get_pool(edge_id, edge_pool_id)[1]
|
|
monitor_id = org_edge_pool.get('monitorId')
|
|
if monitor_id:
|
|
edge_pool['monitorId'] = monitor_id
|
|
|
|
# Keep the current members
|
|
if org_edge_pool.get('member'):
|
|
edge_pool['member'] = org_edge_pool['member']
|
|
|
|
self.vcns.update_pool(edge_id, edge_pool_id, edge_pool)
|
|
|
|
completor(success=True)
|
|
|
|
# if the session_persistence was changed,
|
|
# we may need to update the listener application profile
|
|
if new_pool['listener']:
|
|
old_sess_persist = old_pool['session_persistence']
|
|
new_sess_persist = new_pool['session_persistence']
|
|
|
|
if new_sess_persist != old_sess_persist:
|
|
if not new_pool['listener'].get('default_pool'):
|
|
new_pool['listener']['default_pool'] = new_pool
|
|
listener_mgr.update_app_profile(
|
|
self.vcns, context, new_pool['listener'], edge_id)
|
|
|
|
except nsxv_exc.VcnsApiException:
|
|
with excutils.save_and_reraise_exception():
|
|
completor(success=False)
|
|
LOG.error('Failed to update pool %s', new_pool['id'])
|
|
|
|
def delete(self, context, pool, completor):
|
|
lb_id = pool['loadbalancer_id']
|
|
|
|
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
|
context.session, lb_id)
|
|
if not lb_binding:
|
|
# Don't fail deletion if the resource is already gone
|
|
LOG.warning("Couldn't find LB %s binding during pool deletion",
|
|
lb_id)
|
|
completor(success=True)
|
|
return
|
|
edge_id = lb_binding['edge_id']
|
|
|
|
pool_binding = nsxv_db.get_nsxv_lbaas_pool_binding(
|
|
context.session, lb_id, pool['id'])
|
|
if not pool_binding:
|
|
completor(success=True)
|
|
return
|
|
edge_pool_id = pool_binding['edge_pool_id']
|
|
|
|
listeners_to_update = []
|
|
try:
|
|
if pool['listeners']:
|
|
for listener in pool['listeners']:
|
|
# the pool session persistence may affect the associated
|
|
# pool application profile
|
|
if (pool['session_persistence'] and
|
|
listener['default_pool'] and
|
|
listener['default_pool']['id'] == pool['id']):
|
|
listeners_to_update.append(listener)
|
|
|
|
listener_binding = nsxv_db.get_nsxv_lbaas_listener_binding(
|
|
context.session, lb_id, listener['id'])
|
|
if listener_binding:
|
|
vse = listener_mgr.listener_to_edge_vse(
|
|
context,
|
|
listener,
|
|
lb_binding['vip_address'],
|
|
None,
|
|
listener_binding['app_profile_id'])
|
|
with locking.LockManager.get_lock(edge_id):
|
|
self.vcns.update_vip(
|
|
edge_id, listener_binding['vse_id'], vse)
|
|
self.vcns.delete_pool(edge_id, edge_pool_id)
|
|
completor(success=True)
|
|
nsxv_db.del_nsxv_lbaas_pool_binding(
|
|
context.session, lb_id, pool['id'])
|
|
|
|
for listener in listeners_to_update:
|
|
# need to update the listeners too, now with no default pool
|
|
listener['default_pool'] = None
|
|
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 delete_cascade(self, context, pool, completor):
|
|
self.delete(context, pool, completor)
|
|
|
|
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
|