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
This commit is contained in:
Anna Khmelnitsky 2016-12-08 13:45:45 -08:00 committed by Adit Sarfaty
parent 04730c324c
commit a966ca0708
4 changed files with 101 additions and 82 deletions

View File

@ -808,6 +808,12 @@ class EdgeApplianceDriver(object):
router_id) router_id)
return 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'] server_ip = syslog_config['server_ip']
request = {'featureType': 'syslog', request = {'featureType': 'syslog',
'protocol': protocol, 'protocol': protocol,
@ -820,3 +826,8 @@ class EdgeApplianceDriver(object):
syslog_config['server2_ip']) syslog_config['server2_ip'])
self.vcns.update_edge_syslog(edge_id, request) 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)

View File

@ -57,6 +57,12 @@ LOG = logging.getLogger(__name__)
_uuid = uuidutils.generate_uuid _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(): def _get_vdr_transit_network_ipobj():
transit_net = cfg.CONF.nsxv.vdr_transit_network transit_net = cfg.CONF.nsxv.vdr_transit_network
return netaddr.IPNetwork(transit_net) 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')) 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): class NsxVCallbacks(object):
"""Edge callback implementation Callback functions for """Edge callback implementation Callback functions for
asynchronous tasks. asynchronous tasks.

View File

@ -17,6 +17,7 @@ import logging
import pprint import pprint
import textwrap 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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)) 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): def change_edge_loglevel(properties):
"""Update log level on edge """Update log level on edge
@ -272,34 +232,17 @@ def change_edge_loglevel(properties):
succeeded) succeeded)
""" """
supported_modules = ('routing', 'highavailability',
'dhcp', 'loadbalancer', 'dns')
supported_levels = ('none', 'debug', 'info', 'warning', 'error')
modules = {} modules = {}
if properties.get('log-level'): if properties.get('log-level'):
level = properties.get('log-level') level = properties.get('log-level')
if level in supported_levels: # change log level for all modules
# change log level for all modules modules = {k: level for k in edge_utils.SUPPORTED_EDGE_LOG_MODULES}
modules = {k: level for k in supported_modules}
else:
LOG.info(_LI("Skipping unrecognized level (%s)"), level)
return True
else: else:
# check for log level settings for specific modules # check for log level settings for specific modules
for k, v in properties.items(): for k, v in properties.items():
if k.endswith('-log-level'): if k.endswith('-log-level'):
module = k[:-10] # module is in parameter prefix module = k[:-10] # module is in parameter prefix
if module in supported_modules: modules[module] = v
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
if not modules: if not modules:
# no log level properties # no log level properties
@ -308,15 +251,13 @@ def change_edge_loglevel(properties):
edge_id = properties.get('edge-id') edge_id = properties.get('edge-id')
for module, level in modules.items(): 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: try:
if level == 'none': edge_utils.update_edge_loglevel(nsxv, edge_id, module, level)
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))
except nsxv_exceptions.ResourceNotFound as e: except nsxv_exceptions.ResourceNotFound as e:
LOG.error(_LE("Edge %s not found"), edge_id) LOG.error(_LE("Edge %s not found"), edge_id)

View File

@ -4891,10 +4891,10 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase,
# and needs to be validated separately # and needs to be validated separately
if 'syslog' in expected_data.keys(): if 'syslog' in expected_data.keys():
self.assertSyslogConfig(expected_data['syslog']) self.assertSyslogConfig(expected_data['syslog'])
del expected_data['syslog']
for key, expected_val in expected_data.items(): 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): def test_router_create_with_flavor_different_sizes(self):
"""Create exclusive router with size in flavor """Create exclusive router with size in flavor
@ -4975,20 +4975,22 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase,
self._test_router_create_with_flavor( self._test_router_create_with_flavor(
metainfo, expected_router) metainfo, expected_router)
# Advanced config - secondary server IP and protocol # Advanced config - secondary server IP, protocol and loglevel
ip2 = '1.1.1.11' ip2 = '1.1.1.11'
for protocol in ['tcp', 'udp']: for protocol in ['tcp', 'udp']:
expected_router = {'router_type': 'exclusive', for loglevel in ['none', 'debug', 'info', 'warning', 'error']:
'syslog': {'protocol': protocol, expected_router = {'router_type': 'exclusive',
'server_ip': ip, 'server2_ip': ip2}} 'syslog': {'protocol': protocol,
'server_ip': ip, 'server2_ip': ip2}}
metainfo = ("{'router_type':'exclusive'," metainfo = ("{'router_type':'exclusive',"
"'syslog':{'server_ip':'%s', 'server2_ip':'%s'," "'syslog':{'server_ip':'%s', 'server2_ip':'%s',"
"'protocol':'%s'}}" % (ip, ip2, protocol)) "'protocol':'%s', 'log_level':'%s'}}" %
(ip, ip2, protocol, loglevel))
self._iteration += 1 self._iteration += 1
self._test_router_create_with_flavor( self._test_router_create_with_flavor(
metainfo, expected_router) metainfo, expected_router)
def test_router_create_with_syslog_flavor_error(self): def test_router_create_with_syslog_flavor_error(self):
"""Create router based on flavor with badly formed syslog metadata """Create router based on flavor with badly formed syslog metadata
@ -5001,7 +5003,9 @@ class TestRouterFlavorTestCase(extension.ExtensionTestCase,
self._iteration = 0 self._iteration = 0
bad_defs = ("'server_ip':'1.1.1.1', 'protocol':'http2'", bad_defs = ("'server_ip':'1.1.1.1', 'protocol':'http2'",
"'server2_ip':'2.2.2.2'", "'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: for meta in bad_defs:
metainfo = "{'router_type':'exclusive', 'syslog': {%s}}" % meta metainfo = "{'router_type':'exclusive', 'syslog': {%s}}" % meta