From a966ca0708a5381505efe394404811e9357ee464 Mon Sep 17 00:00:00 2001 From: Anna Khmelnitsky Date: Thu, 8 Dec 2016 13:45:45 -0800 Subject: [PATCH] NSX-V: Add support for log level in router flavors Add the ability to configure routing log level in syslog section of router flavor. For that purpose, move log level configuration modifiers to edge_utils from nsx-admin code. Change-Id: Ic8ea0def221b48ac592b81424cdab7c9cafe0c2b --- .../nsx_v/vshield/edge_appliance_driver.py | 11 +++ .../plugins/nsx_v/vshield/edge_utils.py | 63 +++++++++++++++ .../admin/plugins/nsxv/resources/edges.py | 79 +++---------------- vmware_nsx/tests/unit/nsx_v/test_plugin.py | 30 ++++--- 4 files changed, 101 insertions(+), 82 deletions(-) diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py index 0184409364..819b9458f9 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py @@ -808,6 +808,12 @@ class EdgeApplianceDriver(object): router_id) return + loglevel = syslog_config.get('log_level') + if loglevel and loglevel not in edge_utils.SUPPORTED_EDGE_LOG_LEVELS: + LOG.warning(_LW("Invalid loglevel in syslog config for %s"), + router_id) + return + server_ip = syslog_config['server_ip'] request = {'featureType': 'syslog', 'protocol': protocol, @@ -820,3 +826,8 @@ class EdgeApplianceDriver(object): syslog_config['server2_ip']) self.vcns.update_edge_syslog(edge_id, request) + + # update log level for routing in separate API call + if loglevel: + edge_utils.update_edge_loglevel(self.vcns, edge_id, + 'routing', loglevel) diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py index 0636c80c2f..cfa67ecb11 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py @@ -57,6 +57,12 @@ LOG = logging.getLogger(__name__) _uuid = uuidutils.generate_uuid +SUPPORTED_EDGE_LOG_MODULES = ('routing', 'highavailability', + 'dhcp', 'loadbalancer', 'dns') + +SUPPORTED_EDGE_LOG_LEVELS = ('none', 'debug', 'info', 'warning', 'error') + + def _get_vdr_transit_network_ipobj(): transit_net = cfg.CONF.nsxv.vdr_transit_network return netaddr.IPNetwork(transit_net) @@ -2396,6 +2402,63 @@ def check_network_in_use_at_backend(context, network_id): LOG.error(_LE('NSXv: network is still in use at the backend')) +def default_loglevel_modifier(config, level): + """Modify log level settings in edge config bulk (standard syntax)""" + + if 'logging' not in config: + LOG.error(_LE("Logging section missing in configuration")) + return False + + enable = True + if level == 'none': + enable = False + level = 'info' # default + + config['logging']['enable'] = enable + config['logging']['logLevel'] = level + return True + + +def routing_loglevel_modifier(config, level): + """Modify log level in routing global settings""" + + if 'routingGlobalConfig' not in config: + LOG.error(_LE("routingGlobalConfig section missing in config")) + return False + + return default_loglevel_modifier(config['routingGlobalConfig'], + level) + + +def get_loglevel_modifier(module, level): + """Pick modifier according to module and set log level""" + special_modifiers = {'routing': routing_loglevel_modifier} + + modifier = default_loglevel_modifier + if module in special_modifiers.keys(): + modifier = special_modifiers[module] + + def wrapper(config): + return modifier(config, level) + + return wrapper + + +def update_edge_loglevel(vcns, edge_id, module, level): + """Update loglevel on edge for specified module""" + if module not in SUPPORTED_EDGE_LOG_MODULES: + LOG.error(_LE("Unrecognized logging module %s - ignored"), module) + return + + if level not in SUPPORTED_EDGE_LOG_LEVELS: + LOG.error(_LE("Unrecognized log level %s - ignored"), level) + return + + vcns.update_edge_config_with_modifier(edge_id, module, + get_loglevel_modifier(module, + level)) + + class NsxVCallbacks(object): """Edge callback implementation Callback functions for asynchronous tasks. diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py index ea46d2ab87..fca8d6d01b 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py @@ -17,6 +17,7 @@ import logging import pprint import textwrap +from vmware_nsx.plugins.nsx_v.vshield import edge_utils from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters @@ -222,47 +223,6 @@ def delete_edge_syslog(edge_id): LOG.error(_LE("%s"), str(e)) -def default_loglevel_modifier(config, level): - """Modify log level settings in edge config bulk (standard syntax)""" - - if 'logging' not in config: - LOG.error(_LE("Logging section missing in configuration")) - return False - - enable = True - if level == 'none': - enable = False - level = 'info' # default - - config['logging']['enable'] = enable - config['logging']['logLevel'] = level - return True - - -def routing_loglevel_modifier(config, level): - """Modify log level in routing global settings""" - - if 'routingGlobalConfig' not in config: - LOG.error(_LE("routingGlobalConfig section missing in configuration")) - return False - - return default_loglevel_modifier(config['routingGlobalConfig'], level) - - -def get_loglevel_modifier(module, level): - """This function picks modifier according to module and sets log level""" - special_modifiers = {'routing': routing_loglevel_modifier} - - modifier = default_loglevel_modifier - if module in special_modifiers.keys(): - modifier = special_modifiers[module] - - def wrapper(config): - return modifier(config, level) - - return wrapper - - def change_edge_loglevel(properties): """Update log level on edge @@ -272,34 +232,17 @@ def change_edge_loglevel(properties): succeeded) """ - supported_modules = ('routing', 'highavailability', - 'dhcp', 'loadbalancer', 'dns') - supported_levels = ('none', 'debug', 'info', 'warning', 'error') - modules = {} if properties.get('log-level'): level = properties.get('log-level') - if level in supported_levels: - # change log level for all modules - modules = {k: level for k in supported_modules} - else: - LOG.info(_LI("Skipping unrecognized level (%s)"), level) - return True + # change log level for all modules + modules = {k: level for k in edge_utils.SUPPORTED_EDGE_LOG_MODULES} else: # check for log level settings for specific modules for k, v in properties.items(): if k.endswith('-log-level'): module = k[:-10] # module is in parameter prefix - if module in supported_modules: - if v in supported_levels: - modules[module] = v - else: - LOG.info(_LI("Skipping unrecognized level (%s)"), v) - return True - - else: - LOG.info(_LI("Skipping unrecognized module (%s)"), k) - return True + modules[module] = v if not modules: # no log level properties @@ -308,15 +251,13 @@ def change_edge_loglevel(properties): edge_id = properties.get('edge-id') for module, level in modules.items(): + if level == 'none': + LOG.info(_LI("Disabling logging for %s"), module) + else: + LOG.info(_LI("Enabling logging for %(m)s with level %(l)s"), + {'m': module, 'l': level}) try: - if level == 'none': - LOG.info(_LI("Disabling logging for %s"), module) - else: - LOG.info(_LI("Enabling logging for %(m)s with level %(l)s"), - {'m': module, 'l': level}) - - nsxv.update_edge_config_with_modifier(edge_id, module, - get_loglevel_modifier(module, level)) + edge_utils.update_edge_loglevel(nsxv, edge_id, module, level) except nsxv_exceptions.ResourceNotFound as e: LOG.error(_LE("Edge %s not found"), edge_id) diff --git a/vmware_nsx/tests/unit/nsx_v/test_plugin.py b/vmware_nsx/tests/unit/nsx_v/test_plugin.py index 714915ca11..08df8f45a5 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v/test_plugin.py @@ -4891,10 +4891,10 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase, # and needs to be validated separately if 'syslog' in expected_data.keys(): self.assertSyslogConfig(expected_data['syslog']) - del expected_data['syslog'] for key, expected_val in expected_data.items(): - self.assertEqual(expected_val, router[key]) + if key != 'syslog': + self.assertEqual(expected_val, router[key]) def test_router_create_with_flavor_different_sizes(self): """Create exclusive router with size in flavor @@ -4975,20 +4975,22 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase, self._test_router_create_with_flavor( metainfo, expected_router) - # Advanced config - secondary server IP and protocol + # Advanced config - secondary server IP, protocol and loglevel ip2 = '1.1.1.11' for protocol in ['tcp', 'udp']: - expected_router = {'router_type': 'exclusive', - 'syslog': {'protocol': protocol, - 'server_ip': ip, 'server2_ip': ip2}} + for loglevel in ['none', 'debug', 'info', 'warning', 'error']: + expected_router = {'router_type': 'exclusive', + 'syslog': {'protocol': protocol, + 'server_ip': ip, 'server2_ip': ip2}} - metainfo = ("{'router_type':'exclusive'," - "'syslog':{'server_ip':'%s', 'server2_ip':'%s'," - "'protocol':'%s'}}" % (ip, ip2, protocol)) + metainfo = ("{'router_type':'exclusive'," + "'syslog':{'server_ip':'%s', 'server2_ip':'%s'," + "'protocol':'%s', 'log_level':'%s'}}" % + (ip, ip2, protocol, loglevel)) - self._iteration += 1 - self._test_router_create_with_flavor( - metainfo, expected_router) + self._iteration += 1 + self._test_router_create_with_flavor( + metainfo, expected_router) def test_router_create_with_syslog_flavor_error(self): """Create router based on flavor with badly formed syslog metadata @@ -5001,7 +5003,9 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase, self._iteration = 0 bad_defs = ("'server_ip':'1.1.1.1', 'protocol':'http2'", "'server2_ip':'2.2.2.2'", - "'protocol':'tcp'") + "'protocol':'tcp'", + "'server_ip':'1.1.1.1', 'protocol':'udp','log_level':'pro'", + "'log_level':'error'") for meta in bad_defs: metainfo = "{'router_type':'exclusive', 'syslog': {%s}}" % meta