NSX|V AdminUtil handle orphaned router vnics

If deleting a router interface in the backend fails, the neutron port is
deleted, but the NSX backend interface and the vnic DB entry are not
deleted.
This new admin utility will list and clean those.

Change-Id: I002cac9c04f844c798097cf79d31dcefdea976ed
This commit is contained in:
Adit Sarfaty 2017-09-11 16:14:13 +03:00
parent 123f92b45a
commit 2a4ff322eb
4 changed files with 115 additions and 0 deletions

View File

@ -98,6 +98,17 @@ Orphaned Router bindings
nsxadmin -r orphaned-bindings -o clean
Orphaned Router VNICs
~~~~~~~~~~~~~~~~~~~~~
- List orphaned router vnic entries (exist on the edge vnics bindings DB table, but the neutron interface port behind them is missing)::
nsxadmin -r orphaned-vnics -o list
- Clean orphaned router vnics (delete DB entry, and NSX router interface)::
nsxadmin -r orphaned-vnics -o clean
Missing Edges
~~~~~~~~~~~~~

View File

@ -49,6 +49,7 @@ SPOOFGUARD_POLICY = 'spoofguard-policy'
BACKUP_EDGES = 'backup-edges'
ORPHANED_EDGES = 'orphaned-edges'
ORPHANED_BINDINGS = 'orphaned-bindings'
ORPHANED_VNICS = 'orphaned-vnics'
MISSING_EDGES = 'missing-edges'
METADATA = 'metadata'
MISSING_NETWORKS = 'missing-networks'

View File

@ -14,6 +14,7 @@
from vmware_nsx.shell.admin.plugins.common import constants
from vmware_nsx.shell.admin.plugins.common import formatters
import vmware_nsx.shell.admin.plugins.common.utils as admin_utils
import vmware_nsx.shell.admin.plugins.nsxv.resources.utils as utils
import vmware_nsx.shell.resources as shell
@ -186,6 +187,7 @@ def nsx_recreate_router_or_edge(resource, event, trigger, **kwargs):
return nsx_recreate_router(router_id)
@admin_utils.output_header
def migrate_distributed_routers_dhcp(resource, event, trigger, **kwargs):
context = n_context.get_admin_context()
nsxv = utils.get_nsxv_client()
@ -208,6 +210,96 @@ def migrate_distributed_routers_dhcp(resource, event, trigger, **kwargs):
nsxv.update_routes(edge_id, route_obj)
@admin_utils.output_header
def list_orphaned_vnics(resource, event, trigger, **kwargs):
"""List router orphaned router vnics where the port was deleted"""
orphaned_vnics = get_orphaned_vnics()
if not orphaned_vnics:
LOG.info("No orphaned router vnics found")
return
headers = ['edge_id', 'vnic_index', 'tunnel_index', 'network_id']
LOG.info(formatters.output_formatter(constants.ORPHANED_VNICS,
orphaned_vnics, headers))
def get_orphaned_vnics():
orphaned_vnics = []
context = n_context.get_admin_context()
vnic_binds = nsxv_db.get_edge_vnic_bindings_with_networks(
context.session)
with utils.NsxVPluginWrapper() as plugin:
for vnic_bind in vnic_binds:
edge_id = vnic_bind['edge_id']
# check if this is a router edge by the router bindings table
router_bindings = nsxv_db.get_nsxv_router_bindings_by_edge(
context.session, edge_id)
if not router_bindings:
# Only log it. this is a different type of orphaned
LOG.warning("Router bindings for vnic %s not found", vnic_bind)
continue
router_ids = [b['router_id'] for b in router_bindings]
routers = plugin.get_routers(context,
filters={'id': router_ids})
if routers:
interface_found = False
# check if any of those routers is attached to this network
for router in routers:
if plugin._get_router_interface_ports_by_network(
context, router['id'], vnic_bind['network_id']):
interface_found = True
break
if not interface_found:
# for later deleting the interface we need to know if this
# is a distributed router.
# All the routers on the same edge are of the same type,
# so we can check the first one.
vnic_bind['distributed'] = routers[0].get('distributed')
orphaned_vnics.append(vnic_bind)
return orphaned_vnics
@admin_utils.output_header
def clean_orphaned_vnics(resource, event, trigger, **kwargs):
"""List router orphaned router vnics where the port was deleted"""
orphaned_vnics = get_orphaned_vnics()
if not orphaned_vnics:
LOG.info("No orphaned router vnics found")
return
headers = ['edge_id', 'vnic_index', 'tunnel_index', 'network_id']
LOG.info(formatters.output_formatter(constants.ORPHANED_VNICS,
orphaned_vnics, headers))
user_confirm = admin_utils.query_yes_no("Do you want to delete "
"orphaned vnics",
default="no")
if not user_confirm:
LOG.info("NSXv vnics deletion aborted by user")
return
context = n_context.get_admin_context()
with utils.NsxVPluginWrapper() as plugin:
nsxv_manager = vcns_driver.VcnsDriver(
edge_utils.NsxVCallbacks(plugin))
for vnic in orphaned_vnics:
if not vnic['distributed']:
try:
nsxv_manager.vcns.delete_interface(
vnic['edge_id'], vnic['vnic_index'])
except Exception as e:
LOG.error("Failed to delete vnic from NSX: %s", e)
nsxv_db.free_edge_vnic_by_network(
context.session, vnic['edge_id'], vnic['network_id'])
else:
try:
nsxv_manager.vcns.delete_vdr_internal_interface(
vnic['edge_id'], vnic['vnic_index'])
except Exception as e:
LOG.error("Failed to delete vnic from NSX: %s", e)
nsxv_db.delete_edge_vnic_binding_by_network(
context.session, vnic['edge_id'], vnic['network_id'])
registry.subscribe(nsx_recreate_router_or_edge,
constants.ROUTERS,
shell.Operations.NSX_RECREATE.value)
@ -215,3 +307,11 @@ registry.subscribe(nsx_recreate_router_or_edge,
registry.subscribe(migrate_distributed_routers_dhcp,
constants.ROUTERS,
shell.Operations.MIGRATE_VDR_DHCP.value)
registry.subscribe(list_orphaned_vnics,
constants.ORPHANED_VNICS,
shell.Operations.NSX_LIST.value)
registry.subscribe(clean_orphaned_vnics,
constants.ORPHANED_VNICS,
shell.Operations.NSX_CLEAN.value)

View File

@ -186,6 +186,9 @@ nsxv_resources = {
constants.ROUTERS: Resource(constants.ROUTERS,
[Operations.NSX_RECREATE.value,
Operations.MIGRATE_VDR_DHCP.value]),
constants.ORPHANED_VNICS: Resource(constants.ORPHANED_VNICS,
[Operations.NSX_LIST.value,
Operations.NSX_CLEAN.value]),
constants.CONFIG: Resource(constants.CONFIG,
[Operations.VALIDATE.value]),
constants.BGP_GW_EDGE: Resource(constants.BGP_GW_EDGE,