From edac5ce48c9889d016d4e26a0e1959a6227cc496 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Thu, 11 Apr 2019 14:09:59 +0300 Subject: [PATCH] NSX|V3 adminUtils: detect and clean orphaned section rules nsxadmin -r orphaned-firewall-sections -o nsx-list/clean will now also detect/delete orphaned rules inside nsx sections that belong to neutron security groups. Change-Id: I7f733676e29f6a2b1177b4155e5b36aee3670438 --- doc/source/admin_util.rst | 4 +- vmware_nsx/plugins/nsx_v3/plugin.py | 14 +++---- vmware_nsx/plugins/nsx_v3/utils.py | 38 ++++++++++++++++++ .../plugins/nsxv3/resources/securitygroups.py | 40 +++++++++++++++++++ 4 files changed, 86 insertions(+), 10 deletions(-) diff --git a/doc/source/admin_util.rst b/doc/source/admin_util.rst index b75addb6ff..f103bacd4b 100644 --- a/doc/source/admin_util.rst +++ b/doc/source/admin_util.rst @@ -429,11 +429,11 @@ Firewall Sections Orphaned Firewall Sections ~~~~~~~~~~~~~~~~~~~~~~~~~~ -- List orphaned firewall sections (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB):: +- List orphaned firewall sections & rules (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB):: nsxadmin -r orphaned-firewall-sections -o nsx-list -- Delete orphaned firewall sections (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB):: +- Delete orphaned firewall sections & rules (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB):: nsxadmin -r orphaned-firewall-sections -o nsx-clean diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 65b6495b71..3ff4e240b5 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -127,8 +127,6 @@ NSX_V3_NON_VIF_ENS_PROFILE = \ 'nsx-default-switch-security-non-vif-profile-for-ens' NSX_V3_SERVER_SSL_PROFILE = 'nsx-default-server-ssl-profile' NSX_V3_CLIENT_SSL_PROFILE = 'nsx-default-client-ssl-profile' -# Default UUID for the global OS rule -NSX_V3_OS_DFW_UUID = '00000000-def0-0000-0fed-000000000000' @resource_extend.has_resource_extenders @@ -295,11 +293,11 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, found_sg = False try: super(NsxV3Plugin, self).get_security_group( - context, NSX_V3_OS_DFW_UUID, fields=['id']) + context, v3_utils.NSX_V3_OS_DFW_UUID, fields=['id']) except ext_sg.SecurityGroupNotFound: LOG.warning('Creating a global security group') sec_group = {'security_group': - {'id': NSX_V3_OS_DFW_UUID, + {'id': v3_utils.NSX_V3_OS_DFW_UUID, 'tenant_id': nsx_constants.INTERNAL_V3_TENANT_ID, 'name': 'NSX Internal', 'description': ''}} @@ -324,7 +322,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, # check if the section and nsgroup are already in the DB. If not # it means another server is creating them right now. nsgroup_id, section_id = nsx_db.get_sg_mappings( - context.session, NSX_V3_OS_DFW_UUID) + context.session, v3_utils.NSX_V3_OS_DFW_UUID) if nsgroup_id is None or section_id is None: LOG.info("Global security exists without NSX objects") # Wait a bit to let the other server finish @@ -352,7 +350,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, self._ensure_default_rules() # Validate if there is a race between processes nsgroup_id, section_id = nsx_db.get_sg_mappings( - ctx.session, NSX_V3_OS_DFW_UUID) + ctx.session, v3_utils.NSX_V3_OS_DFW_UUID) LOG.debug("Default NSGroup - %s, Section %s", nsgroup_id, section_id) default_ns_group_id = self._default_section_nsgroup.get('id') duplicates = False @@ -362,7 +360,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, LOG.debug("Updating NSGroup - %s, Section %s", default_ns_group_id, self.default_section) nsx_db.save_sg_mappings(ctx, - NSX_V3_OS_DFW_UUID, + v3_utils.NSX_V3_OS_DFW_UUID, default_ns_group_id, self.default_section) except Exception: @@ -3262,7 +3260,7 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, return secgroup_db def _prevent_nsx_internal_sg_modification(self, sg_id): - if sg_id == NSX_V3_OS_DFW_UUID: + if sg_id == v3_utils.NSX_V3_OS_DFW_UUID: msg = _("Cannot modify NSX internal security group") raise n_exc.InvalidInput(error_message=msg) diff --git a/vmware_nsx/plugins/nsx_v3/utils.py b/vmware_nsx/plugins/nsx_v3/utils.py index f340ef4717..0f4fb25a6b 100644 --- a/vmware_nsx/plugins/nsx_v3/utils.py +++ b/vmware_nsx/plugins/nsx_v3/utils.py @@ -50,6 +50,9 @@ PORT_ERROR_TYPE_MISSING = "Missing port" PORT_ERROR_TYPE_PROFILE = "Wrong switching profiles" PORT_ERROR_TYPE_BINDINGS = "Wrong address binding" +# Default UUID for the global OS rule +NSX_V3_OS_DFW_UUID = '00000000-def0-0000-0fed-000000000000' + LOG = logging.getLogger(__name__) @@ -362,6 +365,41 @@ def get_orphaned_firewall_sections(context, nsxlib): return orphaned_sections +def get_security_group_rules_mappings(context): + q = context.session.query( + securitygroup.SecurityGroupRule.id, + nsx_models.NeutronNsxRuleMapping.nsx_id).join( + nsx_models.NeutronNsxRuleMapping).all() + sg_mappings = [{'rule_id': mapp[0], + 'nsx_rule_id': mapp[1]} + for mapp in q] + return sg_mappings + + +def get_orphaned_firewall_section_rules(context, nsxlib): + fw_sections = nsxlib.firewall_section.list() + sg_mappings = get_security_groups_mappings(context) + rules_mappings = get_security_group_rules_mappings(context) + orphaned_rules = [] + nsx_rules_in_mappings = [r['nsx_rule_id'] for r in rules_mappings] + for fw_section in fw_sections: + for sg_db in sg_mappings: + if (fw_section['id'] == sg_db['section-id'] and + sg_db['id'] != NSX_V3_OS_DFW_UUID): + # found the right neutron SG + section_rules = nsxlib.firewall_section.get_rules( + fw_section['id'])['results'] + for nsx_rule in section_rules: + if nsx_rule['id'] not in nsx_rules_in_mappings: + # orphaned rule + orphaned_rules.append( + {'security-group-name': sg_db['name'], + 'security-group-id': sg_db['id'], + 'section-id': fw_section['id'], + 'rule-id': nsx_rule['id']}) + return orphaned_rules + + def get_dhcp_profile_id(nsxlib): profiles = nsxlib.switching_profile.find_by_display_name( NSX_V3_DHCP_PROFILE_NAME) diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py index ff2b49d5d5..90b4b12c44 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/securitygroups.py @@ -298,11 +298,23 @@ def list_orphaned_sections(resource, event, trigger, **kwargs): attrs=['id', 'display_name']) +def list_orphaned_section_rules(resource, event, trigger, **kwargs): + """List orphaned firewall section rules""" + nsxlib = v3_utils.get_connected_nsxlib() + orphaned_rules = plugin_utils.get_orphaned_firewall_section_rules( + neutron_sg.context, nsxlib) + _log_info("orphaned-firewall-section-rules", orphaned_rules, + attrs=['security-group-name', 'security-group-id', + 'section-id', 'rule-id']) + + def clean_orphaned_sections(resource, event, trigger, **kwargs): """Delete orphaned firewall sections from the NSX backend""" nsxlib = v3_utils.get_connected_nsxlib() orphaned_sections = plugin_utils.get_orphaned_firewall_sections( neutron_sg.context, nsxlib) + if not orphaned_sections: + LOG.info("No orphaned nsx sections were found.") for sec in orphaned_sections: try: nsxlib.firewall_section.delete(sec['id']) @@ -313,6 +325,26 @@ def clean_orphaned_sections(resource, event, trigger, **kwargs): LOG.info("Backend firewall section %s was deleted.", sec['id']) +def clean_orphaned_section_rules(resource, event, trigger, **kwargs): + """Delete orphaned firewall section rules from the NSX backend""" + nsxlib = v3_utils.get_connected_nsxlib() + orphaned_rules = plugin_utils.get_orphaned_firewall_section_rules( + neutron_sg.context, nsxlib) + if not orphaned_rules: + LOG.info("No orphaned nsx rules were found.") + for rule in orphaned_rules: + try: + nsxlib.firewall_section.delete_rule( + rule['section-id'], rule['rule-id']) + except Exception as e: + LOG.error("Failed to delete backend firewall section %(sect)s " + "rule %(rule)s: %(e)s.", {'sect': rule['section-id'], + 'rule': rule['rule-id'], + 'e': e}) + else: + LOG.info("Backend firewall rule %s was deleted.", rule['rule-id']) + + def update_security_groups_logging(resource, event, trigger, **kwargs): """Update allowed traffic logging for all neutron security group rules""" errmsg = ("Need to specify log-allowed-traffic property. Add --property " @@ -365,6 +397,14 @@ registry.subscribe(list_orphaned_sections, constants.ORPHANED_FIREWALL_SECTIONS, shell.Operations.NSX_LIST.value) +registry.subscribe(list_orphaned_section_rules, + constants.ORPHANED_FIREWALL_SECTIONS, + shell.Operations.NSX_LIST.value) + registry.subscribe(clean_orphaned_sections, constants.ORPHANED_FIREWALL_SECTIONS, shell.Operations.NSX_CLEAN.value) + +registry.subscribe(clean_orphaned_section_rules, + constants.ORPHANED_FIREWALL_SECTIONS, + shell.Operations.NSX_CLEAN.value)