From 220a185ed0cf73e39f1995df87096f7749e41ee7 Mon Sep 17 00:00:00 2001 From: Kobi Samoray Date: Tue, 5 Jan 2016 12:53:18 +0200 Subject: [PATCH] Rename badly named edge appliance Due to a bug we had cases where an edge appliance is functioning as a DHCP or a router but its rename operation failed. So the edge appliance appears as a backup in NSX although it's not. This change should resolve this condition by determining what the name of the edge should be and rename it accordingly. Change-Id: Icd46d3c36cf86ae965c85fd2133c3ae092d5b5a8 --- .../plugins/nsxv/resources/backup_edges.py | 142 ++++++++++++++++-- vmware_nsx/shell/nsxadmin.py | 6 +- 2 files changed, 137 insertions(+), 11 deletions(-) diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py index 8dfd6b33a1..7b6ababbd4 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py @@ -15,23 +15,27 @@ import logging +from neutron.callbacks import registry +from neutron.common import exceptions +from neutron.db import l3_db +from oslo_utils import uuidutils + +from vmware_nsx._i18n import _LE, _LI +from vmware_nsx.common import locking +from vmware_nsx.common import nsxv_constants +from vmware_nsx.db import nsxv_db +from vmware_nsx.db import nsxv_models +from vmware_nsx.plugins.nsx_v.vshield.common import constants as vcns_const 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.nsxadmin as shell -from neutron.callbacks import registry -from neutron.common import exceptions - -from vmware_nsx._i18n import _LE, _LI -from vmware_nsx.common import locking -from vmware_nsx.db import nsxv_db - LOG = logging.getLogger(__name__) nsxv = utils.get_nsxv_client() +_uuid = uuidutils.generate_uuid def get_nsxv_backup_edges(): @@ -88,8 +92,7 @@ def nsx_clean_backup_edge(resource, event, trigger, **kwargs): LOG.info(_LI("Backup edge deletion aborted by user")) return try: - with locking.LockManager.get_lock( - 'nsx-edge-request', lock_file_prefix='get-'): + with locking.LockManager.get_lock(edge_id, external=True): # Delete from NSXv backend nsxv.delete_edge(edge_id) # Remove bindings from Neutron DB @@ -100,9 +103,128 @@ def nsx_clean_backup_edge(resource, event, trigger, **kwargs): LOG.error(_LE("%s"), str(e)) +@admin_utils.output_header +def nsx_list_name_mismatches(resource, event, trigger, **kwargs): + edges = nsxv.get_edges()[1] + edges = edges['edgePage'].get('data', []) + plugin_nsx_mismatch = [] + edgeapi = utils.NeutronDbClient() + for edge in edges: + rtr_binding = nsxv_db.get_nsxv_router_binding_by_edge( + edgeapi.context.session, edge['id']) + + if (edge['name'].startswith('backup-') + and rtr_binding['router_id'] != edge['name']): + plugin_nsx_mismatch.append( + {'edge_id': edge['id'], + 'edge_name': edge['name'], + 'router_id': rtr_binding['router_id']}) + + LOG.info(formatters.output_formatter( + constants.BACKUP_EDGES, plugin_nsx_mismatch, + ['edge_id', 'edge_name', 'router_id'])) + + +def nsx_fix_name_mismatch(resource, event, trigger, **kwargs): + errmsg = ("Need to specify edge-id property. Add --property " + "edge-id=") + if not kwargs.get('property'): + LOG.error(_LE("%s"), errmsg) + return + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + edgeapi = utils.NeutronDbClient() + edge_id = properties.get('edge-id') + if not edge_id: + LOG.error(_LE("%s"), errmsg) + return + try: + # edge[0] is response status code + # edge[1] is response body + edge = nsxv.get_edge(edge_id)[1] + except exceptions.NeutronException as e: + LOG.error(_LE("%s"), str(e)) + else: + if edge['name'].startswith('backup-'): + + rtr_binding = nsxv_db.get_nsxv_router_binding_by_edge( + edgeapi.context.session, edge['id']) + + if rtr_binding['router_id'] == edge['name']: + LOG.error( + _LE('Edge %s no mismatch with NSX'), edge_id) + return + + try: + with locking.LockManager.get_lock(edge_id, external=True): + # Update edge at NSXv backend + if rtr_binding['router_id'].startswith('dhcp-'): + # Edge is a DHCP edge - just use router_id as name + edge['name'] = rtr_binding['router_id'] + else: + # This is a router - if shared, prefix with 'shared-' + nsx_attr = (edgeapi.context.session.query( + nsxv_models.NsxvRouterExtAttributes).filter_by( + router_id=rtr_binding['router_id']).first()) + if nsx_attr and nsx_attr['router_type'] == 'shared': + edge['name'] = ('shared-' + _uuid())[ + :vcns_const.EDGE_NAME_LEN] + elif (nsx_attr + and nsx_attr['router_type'] == 'exclusive'): + rtr_db = (edgeapi.context.session.query( + l3_db.Router).filter_by( + id=rtr_binding['router_id']).first()) + if rtr_db: + edge['name'] = ( + rtr_db['name'][ + :nsxv_constants.ROUTER_NAME_LENGTH - + len(rtr_db['id'])] + + '-' + rtr_db['id']) + else: + LOG.error( + _LE('No database entry for router id %s'), + rtr_binding['router_id']) + + else: + LOG.error( + _LE('Could not determine the name for ' + 'Edge %s'), edge_id) + return + + confirm = admin_utils.query_yes_no( + "Do you want to rename edge %s to %s" % (edge_id, + edge['name']), + default="no") + + if not confirm: + LOG.info(_LI("Edge rename aborted by user")) + return + LOG.info(_LI("Edge rename started")) + # having these keys fail the NSX transaction + for key in ['status', 'datacenterMoid', 'fqdn', 'version', + 'type', 'tenant', 'datacenterName', + 'hypervisorAssist', 'universal', 'enableFips']: + edge.pop(key, None) + try: + LOG.error(_LE("Update edge...")) + nsxv.update_edge(edge_id, edge) + except Exception as e: + LOG.error(_LE("Update failed - %s"), (e)) + except Exception as e: + LOG.error(_LE("%s"), str(e)) + else: + LOG.error( + _LE('Edge %s has no backup prefix on NSX'), edge_id) + return + registry.subscribe(nsx_list_backup_edges, constants.BACKUP_EDGES, shell.Operations.LIST.value) registry.subscribe(nsx_clean_backup_edge, constants.BACKUP_EDGES, shell.Operations.CLEAN.value) +registry.subscribe(nsx_list_name_mismatches, + constants.BACKUP_EDGES, + shell.Operations.LIST_MISMATCHES.value) +registry.subscribe(nsx_fix_name_mismatch, + constants.BACKUP_EDGES, + shell.Operations.FIX_MISMATCH.value) diff --git a/vmware_nsx/shell/nsxadmin.py b/vmware_nsx/shell/nsxadmin.py index e149da8e3f..35c3dac88c 100644 --- a/vmware_nsx/shell/nsxadmin.py +++ b/vmware_nsx/shell/nsxadmin.py @@ -53,6 +53,8 @@ LOG = logging.getLogger(__name__) class Operations(enum.Enum): LIST = 'list' CLEAN = 'clean' + LIST_MISMATCHES = 'list-mismatches' + FIX_MISMATCH = 'fix-mismatch' NEUTRON_LIST = 'neutron-list' NEUTRON_CLEAN = 'neutron-clean' @@ -84,7 +86,9 @@ nsxv_resources = { Operations.NSX_UPDATE.value]), constants.BACKUP_EDGES: Resource(constants.BACKUP_EDGES, [Operations.LIST.value, - Operations.CLEAN.value]), + Operations.CLEAN.value, + Operations.LIST_MISMATCHES.value, + Operations.FIX_MISMATCH.value]), constants.ORPHANED_EDGES: Resource(constants.ORPHANED_EDGES, [Operations.LIST.value, Operations.CLEAN.value]),