Kobi Samoray 5b2151d976 [NSXP,NSXT] orphaned LBs handling to nsxadmin
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
2021-10-21 10:09:06 +03:00

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)