
Add the options to detect and cleanup loadbalancer services which are allocated in NSX but do not exist in Octavia. The orphaned loadbalancer services prevents routers from being deleted and therefore should be cleaned up prior to the router deletion. Change-Id: Ic0ad5175214cff034bd76a16fc11dbea3ccd6b13
144 lines
5.5 KiB
Python
144 lines
5.5 KiB
Python
# Copyright 2020 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 neutron_lib.callbacks import registry
|
|
from neutron_lib import exceptions as n_exc
|
|
from oslo_log import log as logging
|
|
|
|
from vmware_nsx.services.lbaas.nsx_p.implementation import lb_utils
|
|
from vmware_nsx.services.lbaas.octavia import octavia_listener
|
|
from vmware_nsx.shell.admin.plugins.common import constants
|
|
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
|
|
from vmware_nsx.shell.admin.plugins.nsxp.resources import utils as p_utils
|
|
from vmware_nsx.shell import resources as shell
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def update_lb_service_tags(resource, event, trigger, **kwargs):
|
|
"""Update the LB id tag on existing LB services"""
|
|
nsxpolicy = p_utils.get_connected_nsxpolicy()
|
|
service_client = nsxpolicy.load_balancer.lb_service
|
|
services = service_client.list()
|
|
n_updated = 0
|
|
for lb_service in services:
|
|
# First make sure it i a neutron service
|
|
is_neutron = False
|
|
for tag in lb_service.get('tags', []):
|
|
if tag['scope'] == 'os-api-version':
|
|
is_neutron = True
|
|
break
|
|
if is_neutron:
|
|
# Add a tag with the id of this resource as the first Lb
|
|
# creates the service with its id
|
|
try:
|
|
service_client.update_customized(
|
|
lb_service['id'],
|
|
lb_utils.add_service_tag_callback(lb_service['id'],
|
|
only_first=True))
|
|
except n_exc.BadRequest:
|
|
LOG.warning("Lb service %s already has a loadbalancer tag",
|
|
lb_service['id'])
|
|
else:
|
|
n_updated = n_updated + 1
|
|
|
|
LOG.info("Done updating %s Lb services.", n_updated)
|
|
|
|
|
|
def _orphaned_loadbalancer_handler(handler_callback):
|
|
# Retrieve Octavia loadbalancers
|
|
client = octavia_listener.get_octavia_rpc_client()
|
|
o_endpoint = octavia_listener.NSXOctaviaListenerEndpoint(client=client)
|
|
octavia_lb_ids = o_endpoint.get_active_loadbalancers()
|
|
|
|
# Retrieve NSX list of LB services
|
|
nsxpolicy = p_utils.get_connected_nsxpolicy()
|
|
service_client = nsxpolicy.load_balancer.lb_service
|
|
services = service_client.list()
|
|
|
|
for lb_service in services:
|
|
is_orphan = True
|
|
for tag in lb_service.get('tags', []):
|
|
if (tag['scope'] == 'loadbalancer_id' and
|
|
tag['tag'] in octavia_lb_ids):
|
|
is_orphan = False
|
|
break
|
|
if is_orphan:
|
|
handler_callback(lb_service)
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def list_orphaned_loadbalancers(resource, event, trigger, **kwargs):
|
|
def _orphan_handler(lb_service):
|
|
LOG.warning('NSX loadbalancer service %s has no valid Octavia '
|
|
'loadbalancers', lb_service['id'])
|
|
|
|
_orphaned_loadbalancer_handler(_orphan_handler)
|
|
|
|
|
|
@admin_utils.output_header
|
|
@admin_utils.unpack_payload
|
|
def clean_orphaned_loadbalancers(resource, event, trigger, **kwargs):
|
|
def _orphan_handler(lb_service):
|
|
nsxpolicy = p_utils.get_connected_nsxpolicy()
|
|
nsxp_lb = nsxpolicy.load_balancer
|
|
service_client = nsxp_lb.lb_service
|
|
|
|
# Cleanup virtual servers
|
|
vs_client = nsxp_lb.virtual_server
|
|
vs_list = vs_client.list()
|
|
for vs in vs_list:
|
|
if (vs.get('lb_service_path') and
|
|
vs['lb_service_path'] == lb_service.get('path')):
|
|
try:
|
|
vs_client.delete(vs['id'])
|
|
except Exception as e:
|
|
LOG.error('Failed to delete virtual server %s from NSX '
|
|
'loadbalancer service %s with exception (%s)',
|
|
vs['id'], lb_service['id'], e)
|
|
|
|
# Detach LB service from router
|
|
try:
|
|
service_client.update(lb_service['id'], connectivity_path=None)
|
|
except Exception as e:
|
|
LOG.error('Failed to clean up NSX loadbalancer service %s with '
|
|
'exception (%s)', lb_service['id'], e)
|
|
|
|
# Delete LB service
|
|
try:
|
|
service_client.delete(lb_service['id'])
|
|
LOG.info('Cleaned up NSX loadbalancer service %s from router',
|
|
lb_service['id'])
|
|
except Exception as e:
|
|
LOG.error('Failed to clean up NSX loadbalancer service %s with '
|
|
'exception (%s)', lb_service['id'], e)
|
|
|
|
_orphaned_loadbalancer_handler(_orphan_handler)
|
|
|
|
|
|
registry.subscribe(update_lb_service_tags,
|
|
constants.LB_SERVICES,
|
|
shell.Operations.NSX_UPDATE_TAGS.value)
|
|
|
|
registry.subscribe(list_orphaned_loadbalancers,
|
|
constants.LB_SERVICES,
|
|
shell.Operations.LIST_ORPHANED.value)
|
|
|
|
registry.subscribe(clean_orphaned_loadbalancers,
|
|
constants.LB_SERVICES,
|
|
shell.Operations.CLEAN_ORPHANED.value)
|