NSX|V3: prevent duplicate default FW sections
When the plugin starts it will check if the global NS group and OS DFW section are created on the NSX. If not it will create these. There is a edge case where two servers are started in parallel and they both create the default section. This will lead to traffic being dropped. This is dealt with in the following way: 1. We store the default OS section and NS group in the database 2. If the entries do not exist then we create them, the DB will indicate if there is a duplicate and then the plugin will do a cleanup of the incorrect resources. In order to do this we need asecurity group. A default global one with ID 00000000-def0-0000-0fed-000000000000 is created. If the admin wishes to delete the global section then she/he should: 1. delete the NSX section 2. delete the security group 3. restart the neutron service Change-Id: Ide7a7c75efac3e49d51e522a11c77e754f3d1447
This commit is contained in:
parent
527eca9f73
commit
a96d83ece6
@ -18,3 +18,5 @@ VIF_TYPE_DVS = 'dvs'
|
||||
|
||||
# NSXv3 CORE PLUGIN PATH
|
||||
VMWARE_NSX_V3_PLUGIN_NAME = 'vmware_nsxv3'
|
||||
|
||||
INTERNAL_V3_TENANT_ID = 'v3_internal_project'
|
||||
|
@ -93,6 +93,7 @@ from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.common import l3_rpc_agent_api
|
||||
from vmware_nsx.common import locking
|
||||
from vmware_nsx.common import managers
|
||||
from vmware_nsx.common import nsx_constants
|
||||
from vmware_nsx.common import utils
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.db import extended_security_group
|
||||
@ -135,6 +136,8 @@ NSX_V3_EXCLUDED_PORT_NSGROUP_NAME = 'neutron_excluded_port_nsgroup'
|
||||
NSX_V3_NON_VIF_PROFILE = 'nsx-default-switch-security-non-vif-profile'
|
||||
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'
|
||||
|
||||
|
||||
def inject_headers():
|
||||
@ -217,11 +220,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
def __init__(self):
|
||||
self.fwaas_callbacks = None
|
||||
self._is_sub_plugin = tvd_utils.is_tvd_core_plugin()
|
||||
self.init_is_complete = False
|
||||
nsxlib_utils.set_is_attr_callback(validators.is_attr_set)
|
||||
self._extend_fault_map()
|
||||
if self._is_sub_plugin:
|
||||
extension_drivers = cfg.CONF.nsx_tvd.nsx_v3_extension_drivers
|
||||
self._update_project_mapping()
|
||||
else:
|
||||
extension_drivers = cfg.CONF.nsx_extension_drivers
|
||||
self._extension_manager = managers.ExtensionManager(
|
||||
@ -262,16 +264,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self._translate_configured_names_to_uuids()
|
||||
self._init_dhcp_metadata()
|
||||
|
||||
# Include default section NSGroup
|
||||
LOG.debug("Initializing NSX v3 default section NSGroup")
|
||||
self._default_section_nsgroup = None
|
||||
self._default_section_nsgroup = self._init_default_section_nsgroup()
|
||||
if not self._default_section_nsgroup:
|
||||
msg = _("Unable to initialize NSX v3 default section NSGroup %s"
|
||||
) % NSX_V3_FW_DEFAULT_NS_GROUP
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
|
||||
self.default_section = self._init_default_section_rules()
|
||||
self._prepare_default_rules()
|
||||
self._process_security_group_logging()
|
||||
|
||||
# init profiles on nsx backend
|
||||
@ -314,6 +307,69 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
resources.PROCESS,
|
||||
events.AFTER_INIT)
|
||||
|
||||
def _update_project_mapping(self):
|
||||
ctx = q_context.get_admin_context()
|
||||
try:
|
||||
nsx_db.add_project_plugin_mapping(
|
||||
ctx.session,
|
||||
nsx_constants.INTERNAL_V3_TENANT_ID,
|
||||
projectpluginmap.NsxPlugins.NSX_T)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
pass
|
||||
|
||||
def _ensure_default_rules(self):
|
||||
# Include default section NSGroup
|
||||
LOG.debug("Initializing NSX v3 default section NSGroup")
|
||||
self._default_section_nsgroup = None
|
||||
self._default_section_nsgroup = self._init_default_section_nsgroup()
|
||||
if not self._default_section_nsgroup:
|
||||
msg = _("Unable to initialize NSX v3 default section NSGroup %s"
|
||||
) % NSX_V3_FW_DEFAULT_NS_GROUP
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
self.default_section = self._init_default_section_rules()
|
||||
|
||||
def _ensure_global_sg_placeholder(self, context):
|
||||
try:
|
||||
super(NsxV3Plugin, self).get_security_group(
|
||||
context, NSX_V3_OS_DFW_UUID, fields=['id'])
|
||||
except ext_sg.SecurityGroupNotFound:
|
||||
sec_group = {'security_group':
|
||||
{'id': NSX_V3_OS_DFW_UUID,
|
||||
'tenant_id': nsx_constants.INTERNAL_V3_TENANT_ID,
|
||||
'name': 'NSX Internal',
|
||||
'description': None}}
|
||||
try:
|
||||
# ensure that the global default is created
|
||||
super(NsxV3Plugin, self).create_security_group(
|
||||
context, sec_group, True)
|
||||
except Exception:
|
||||
# Treat a race of multiple processing creating the seg group
|
||||
LOG.warning('Unable to create global security group')
|
||||
|
||||
def _prepare_default_rules(self):
|
||||
ctx = q_context.get_admin_context()
|
||||
# Need a global placeholder as the DB below has a foreign key to
|
||||
# this security group
|
||||
self._ensure_global_sg_placeholder(ctx)
|
||||
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)
|
||||
if nsgroup_id is None or section_id is None:
|
||||
default_ns_group_id = self._default_section_nsgroup.get('id')
|
||||
try:
|
||||
nsx_db.save_sg_mappings(ctx,
|
||||
NSX_V3_OS_DFW_UUID,
|
||||
default_ns_group_id,
|
||||
self.default_section)
|
||||
except Exception:
|
||||
LOG.warning("Duplicate rules created. Cleaning up!")
|
||||
# Delete duplicates created
|
||||
self.nsxlib.firewall_section.delete(self.default_section)
|
||||
self.nsxlib.ns_group.delete(default_ns_group_id)
|
||||
# Ensure global variables are updated
|
||||
self._ensure_default_rules()
|
||||
|
||||
@staticmethod
|
||||
def plugin_type():
|
||||
return projectpluginmap.NsxPlugins.NSX_T
|
||||
|
@ -189,6 +189,12 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase,
|
||||
mock_process_security_group_logging = mock.patch.object(
|
||||
nsx_plugin.NsxV3Plugin, '_process_security_group_logging')
|
||||
mock_process_security_group_logging.start()
|
||||
# need to mock the global placeholder. This is due to the fact that
|
||||
# the generic security group tests assume that there is just one
|
||||
# security group.
|
||||
mock_ensure_global_sg_placeholder = mock.patch.object(
|
||||
nsx_plugin.NsxV3Plugin, '_ensure_global_sg_placeholder')
|
||||
mock_ensure_global_sg_placeholder.start()
|
||||
|
||||
def setUp(self, plugin=PLUGIN_NAME,
|
||||
ext_mgr=None,
|
||||
|
Loading…
Reference in New Issue
Block a user