NSX|V+V3: Move FW section logging update to admin utility

On the plugin init there is a side process going over all the security
group rules in the NSX DFW checking if their logging flag should be
updated according to the global configuration flag.
Since this is relevant only in case the global config flag
log_security_groups_allowed_traffic was updated by the user, which is very rare,
this patch removed it from the code, and replaced it with an admin utility
that can be used.
This will make the plugin initialization process quicker and prevent unnecessary
load on the NSX.

Change-Id: I233915e589b53ccb4b76a3ef3d24bb56c0459e92
This commit is contained in:
Adit Sarfaty 2018-07-31 10:40:23 +03:00
parent 04c0c6c74d
commit dac109662e
11 changed files with 116 additions and 86 deletions

View File

@ -269,6 +269,10 @@ Security Groups, Firewall and Spoofguard
nsxadmin -r security-groups -o migrate-to-policy --property policy-id=policy-10 --property security-group-id=733f0741-fa2c-4b32-811c-b78e4dc8ec39
- Update logging flag of the security groups on the NSX DFW
nsxadmin -r security-groups -o update-logging --property log-allowed-traffic=true
- Spoofguard support::
nsxadmin -r spoofguard-policy -o list-mismatches
@ -390,6 +394,10 @@ Security Groups & NSX Security Groups
nsxadmin -r nsx-security-groups -o migrate-to-dynamic-criteria
- Update logging flag of the security groups on the NSX DFW
nsxadmin -r security-groups -o update-logging --property log-allowed-traffic=true
Firewall Sections
~~~~~~~~~~~~~~~~~

View File

@ -295,7 +295,6 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
"NSX 6.3 onwards")
self.sg_container_id = self._create_security_group_container()
self.default_section = self._create_cluster_default_fw_section()
self._process_security_groups_rules_logging()
self._router_managers = managers.RouterTypeManager(self)
@ -574,47 +573,6 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
section_id = self.nsx_sg_utils.parse_and_get_section_id(c)
return section_id
def _process_security_groups_rules_logging(self):
def process_security_groups_rules_logging(*args, **kwargs):
with locking.LockManager.get_lock('nsx-dfw-section',
lock_file_prefix='dfw-section'):
context = n_context.get_admin_context()
log_allowed = cfg.CONF.nsxv.log_security_groups_allowed_traffic
# If the section/sg is already logged, then no action is
# required.
for sg in [sg for sg in self.get_security_groups(context)
if sg.get(sg_logging.LOGGING) is False]:
if sg.get(sg_policy.POLICY):
# Logging is not relevant with a policy
continue
section_uri = self._get_section_uri(context.session,
sg['id'])
if section_uri is None:
continue
# Section/sg is not logged, update rules logging according
# to the 'log_security_groups_allowed_traffic' config
# option.
try:
h, c = self.nsx_v.vcns.get_section(section_uri)
section = self.nsx_sg_utils.parse_section(c)
section_needs_update = (
self.nsx_sg_utils.set_rules_logged_option(
section, log_allowed))
if section_needs_update:
self.nsx_v.vcns.update_section(
section_uri,
self.nsx_sg_utils.to_xml_string(section), h)
except Exception as exc:
LOG.error('Unable to update security group %(sg)s '
'section for logging. %(e)s',
{'e': exc, 'sg': sg['id']})
c_utils.spawn_n(process_security_groups_rules_logging)
def _create_dhcp_static_binding(self, context, neutron_port_db):
network_id = neutron_port_db['network_id']

View File

@ -274,7 +274,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self._init_dhcp_metadata()
self._prepare_default_rules()
self._process_security_group_logging()
# init profiles on nsx backend
self._init_nsx_profiles()
@ -779,27 +778,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
tags=self.nsxlib.build_v3_api_version_tag())
return self._get_port_security_profile()
def _process_security_group_logging(self):
def process_security_group_logging(*args, **kwargs):
context = q_context.get_admin_context()
log_all_rules = cfg.CONF.nsx_v3.log_security_groups_allowed_traffic
secgroups = self.get_security_groups(context,
fields=['id',
sg_logging.LOGGING])
for sg in [sg for sg in secgroups
if sg.get(sg_logging.LOGGING) is False]:
nsgroup_id, section_id = nsx_db.get_sg_mappings(
context.session, sg['id'])
if section_id:
try:
self.nsxlib.firewall_section.set_rule_logging(
section_id, logging=log_all_rules)
except nsx_lib_exc.ManagerError:
LOG.error("Failed to update firewall rule logging "
"for rule in section %s", section_id)
utils.spawn_n(process_security_group_logging)
def _init_default_section_rules(self):
with locking.LockManager.get_lock('nsxv3_default_section'):
section_description = ("This section is handled by OpenStack to "

View File

@ -31,6 +31,7 @@ from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
from vmware_nsx.db import nsx_models
from vmware_nsx.db import nsxv_db
from vmware_nsx.db import nsxv_models
from vmware_nsx.extensions import securitygrouplogging as sg_logging
from vmware_nsx.extensions import securitygrouppolicy as sg_policy
from vmware_nsx.shell.admin.plugins.common import constants
from vmware_nsx.shell.admin.plugins.common import formatters
@ -464,6 +465,63 @@ def firewall_update_cluster_default_fw_section(resource, event, trigger,
LOG.info("Cluster default FW section updated.")
@admin_utils.output_header
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 "
"log-allowed-traffic=true/false")
if not kwargs.get('property'):
LOG.error("%s", errmsg)
return
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
log_allowed_str = properties.get('log-allowed-traffic')
if not log_allowed_str or log_allowed_str.lower() not in ['true', 'false']:
LOG.error("%s", errmsg)
return
log_allowed = log_allowed_str.lower() == 'true'
context = n_context.get_admin_context()
with utils.NsxVPluginWrapper() as plugin:
vcns = plugin.nsx_v.vcns
sg_utils = plugin. nsx_sg_utils
# If the section/sg is already logged, then no action is
# required.
security_groups = plugin.get_security_groups(context)
LOG.info("Going to update logging of %s sections",
len(security_groups))
for sg in [sg for sg in plugin.get_security_groups(context)
if sg.get(sg_logging.LOGGING) is False]:
if sg.get(sg_policy.POLICY):
# Logging is not relevant with a policy
continue
section_uri = plugin._get_section_uri(context.session,
sg['id'])
if section_uri is None:
continue
# Section/sg is not logged, update rules logging according
# to the 'log_security_groups_allowed_traffic' config
# option.
try:
h, c = vcns.get_section(section_uri)
section = sg_utils.parse_section(c)
section_needs_update = sg_utils.set_rules_logged_option(
section, log_allowed)
if section_needs_update:
vcns.update_section(section_uri,
sg_utils.to_xml_string(section), h)
except Exception as exc:
LOG.error('Unable to update security group %(sg)s '
'section for logging. %(e)s',
{'e': exc, 'sg': sg['id']})
registry.subscribe(update_security_groups_logging,
constants.SECURITY_GROUPS,
shell.Operations.UPDATE_LOGGING.value)
registry.subscribe(migrate_sg_to_policy,
constants.SECURITY_GROUPS,
shell.Operations.MIGRATE_TO_POLICY.value)

View File

@ -75,9 +75,6 @@ class NsxVPluginWrapper(plugin.NsxVPlugin):
# skip getting the Qos policy ID because get_object calls
# plugin init again on admin-util environment
def _process_security_groups_rules_logging(self):
pass
def count_spawn_jobs(self):
# check if there are any spawn jobs running
return self.edge_manager._get_worker_pool().running()

View File

@ -29,6 +29,7 @@ from vmware_nsx.shell.admin.plugins.common import formatters
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils
from vmware_nsx.shell import resources as shell
from vmware_nsxlib.v3 import exceptions as nsx_lib_exc
from vmware_nsxlib.v3 import nsx_constants as consts
from vmware_nsxlib.v3 import security
@ -314,6 +315,46 @@ def clean_orphaned_sections(resource, event, trigger, **kwargs):
LOG.info("Backend firewall section %s was deleted.", sec['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 "
"log-allowed-traffic=true/false")
if not kwargs.get('property'):
LOG.error("%s", errmsg)
return
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
log_allowed_str = properties.get('log-allowed-traffic')
if not log_allowed_str or log_allowed_str.lower() not in ['true', 'false']:
LOG.error("%s", errmsg)
return
log_allowed = log_allowed_str.lower() == 'true'
context = neutron_context.get_admin_context()
nsxlib = v3_utils.get_connected_nsxlib()
with v3_utils.NsxV3PluginWrapper() as plugin:
secgroups = plugin.get_security_groups(context,
fields=['id',
sg_logging.LOGGING])
LOG.info("Going to update logging of %s sections",
len(secgroups))
for sg in [sg for sg in secgroups
if sg.get(sg_logging.LOGGING) is False]:
nsgroup_id, section_id = nsx_db.get_sg_mappings(
context.session, sg['id'])
if section_id:
try:
nsxlib.firewall_section.set_rule_logging(
section_id, logging=log_allowed)
except nsx_lib_exc.ManagerError:
LOG.error("Failed to update firewall rule logging "
"for rule in section %s", section_id)
registry.subscribe(update_security_groups_logging,
constants.SECURITY_GROUPS,
shell.Operations.UPDATE_LOGGING.value)
registry.subscribe(migrate_nsgroups_to_dynamic_criteria,
constants.FIREWALL_NSX_GROUPS,
shell.Operations.MIGRATE_TO_DYNAMIC_CRITERIA.value)

View File

@ -169,9 +169,6 @@ class NsxV3PluginWrapper(plugin.NsxV3Plugin):
def _init_dhcp_metadata(self):
pass
def _process_security_group_logging(self):
pass
def _extend_get_network_dict_provider(self, context, net):
self._extend_network_dict_provider(context, net)
# skip getting the Qos policy ID because get_object calls

View File

@ -59,6 +59,7 @@ class Operations(enum.Enum):
MIGRATE_TO_DYNAMIC_CRITERIA = 'migrate-to-dynamic-criteria'
NSX_MIGRATE_V_V3 = 'nsx-migrate-v-v3'
MIGRATE_TO_POLICY = 'migrate-to-policy'
UPDATE_LOGGING = 'update-logging'
NSX_MIGRATE_EXCLUDE_PORTS = 'migrate-exclude-ports'
MIGRATE_VDR_DHCP = 'migrate-vdr-dhcp'
STATUS = 'status'
@ -80,7 +81,8 @@ class Resource(object):
nsxv3_resources = {
constants.SECURITY_GROUPS: Resource(constants.SECURITY_GROUPS,
[Operations.LIST.value,
Operations.FIX_MISMATCH.value]),
Operations.FIX_MISMATCH.value,
Operations.UPDATE_LOGGING.value]),
constants.FIREWALL_SECTIONS: Resource(constants.FIREWALL_SECTIONS,
[Operations.LIST.value,
Operations.LIST_MISMATCHES.value]),
@ -186,7 +188,8 @@ nsxv_resources = {
constants.SECURITY_GROUPS: Resource(constants.SECURITY_GROUPS,
[Operations.LIST.value,
Operations.FIX_MISMATCH.value,
Operations.MIGRATE_TO_POLICY.value]),
Operations.MIGRATE_TO_POLICY.value,
Operations.UPDATE_LOGGING.value]),
constants.FIREWALL_NSX_GROUPS: Resource(
constants.FIREWALL_NSX_GROUPS, [Operations.LIST.value,
Operations.LIST_MISMATCHES.value]),

View File

@ -214,10 +214,6 @@ class NsxVPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
mock_deploy_backup_edges_at_backend = mock.patch("%s.%s" % (
vmware.EDGE_MANAGE_NAME, '_deploy_backup_edges_at_backend'))
mock_deploy_backup_edges_at_backend.start()
mock_process_security_group_logging = mock.patch(
'vmware_nsx.plugin.NsxVPlugin.'
'_process_security_groups_rules_logging')
mock_process_security_group_logging.start()
self.default_res_pool = 'respool-28'
cfg.CONF.set_override("resource_pool_id", self.default_res_pool,
@ -3988,10 +3984,6 @@ class NsxVSecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase):
mock_check_backup_edge_pools = mock.patch("%s.%s" % (
vmware.EDGE_MANAGE_NAME, '_check_backup_edge_pools'))
mock_check_backup_edge_pools.start()
mock_process_security_group_logging = mock.patch(
'vmware_nsx.plugin.NsxVPlugin.'
'_process_security_groups_rules_logging')
mock_process_security_group_logging.start()
c_utils.spawn_n = mock.Mock(side_effect=lambda f: f())
super(NsxVSecurityGroupsTestCase, self).setUp(plugin=plugin,

View File

@ -197,10 +197,6 @@ class NsxV3PluginTestCaseMixin(test_plugin.NeutronDbPluginV2TestCase,
'neutron.scheduler.dhcp_agent_scheduler.AZAwareWeightScheduler')
def mock_plugin_methods(self):
# mock unnecessary call which causes spawn
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.

View File

@ -220,7 +220,8 @@ class TestNsxvAdminUtils(AbstractTestAdminUtils,
"security-group-id=sg-1",
"dvs-id=dvs-1",
"moref=virtualwire-1",
"teamingpolicy=LACP_ACTIVE"
"teamingpolicy=LACP_ACTIVE",
"log-allowed-traffic=true"
]
self._test_resources_with_args(
resources.nsxv_resources, args)
@ -281,7 +282,8 @@ class TestNsxv3AdminUtils(AbstractTestAdminUtils,
"metadata_proxy_uuid=e5b9b249-0034-4729-8ab6-fe4dacaa3a12",
"nsx-id=e5b9b249-0034-4729-8ab6-fe4dacaa3a12",
"availability-zone=default",
"server-ip=1.1.1.1"
"server-ip=1.1.1.1",
"log-allowed-traffic=true"
]
# Create some neutron objects for the utilities to run on
self._create_router()