diff --git a/doc/source/admin_util.rst b/doc/source/admin_util.rst index 09de6d8623..1ba471573c 100644 --- a/doc/source/admin_util.rst +++ b/doc/source/admin_util.rst @@ -48,6 +48,18 @@ Edges nsxadmin -o nsx-update -r edges -p edge-id=edge-55 --property syslog-server=none +- Enable logging with specified log level for specific module (routing, dns, dhcp, highavailability, loadbalancer) on edge:: + + nsxadmin -o nsx-update -r edges -p edge-id=edge-55 --property routing-log-level=debug + +- Enable logging with specified log level for all supported modules on edge:: + + nsxadmin -o nsx-update -r edges -p edge-id=edge-55 --property log-level=debug + +- Disable logging on edge:: + + nsxadmin -o nsx-update -r edges -p edge-id=edge-55 --property log-level=none + - Update reservations of an edge:: nsxadmin -o nsx-update -r edges -p edge-id=edge-55 --property resource= --property limit= --property reservation= --property shares= diff --git a/vmware_nsx/plugins/nsx_v/vshield/vcns.py b/vmware_nsx/plugins/nsx_v/vshield/vcns.py index ed1dd2b613..3e43e65752 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/vcns.py +++ b/vmware_nsx/plugins/nsx_v/vshield/vcns.py @@ -248,6 +248,12 @@ class Vcns(object): uri = "%s/%s/syslog/config" % (URI_PREFIX, edge_id) return self.do_request(HTTP_DELETE, uri) + def update_edge_config_with_modifier(self, edge_id, module, modifier): + uri = "%s/%s/%s/config" % (URI_PREFIX, edge_id, module) + config = self.do_request(HTTP_GET, uri)[1] + if modifier(config): + return self.do_request(HTTP_PUT, uri, config) + def get_edge_interfaces(self, edge_id): uri = "%s/%s/interfaces" % (URI_PREFIX, edge_id) return self.do_request(HTTP_GET, uri, decode=True) diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py index ecc6e59536..ea46d2ab87 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/edges.py @@ -222,6 +222,111 @@ 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 + + Update log level either for specific module or for all modules. + 'none' disables logging, any other level enables logging + Returns True if found any log level properties (regardless if action + 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 + 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 + + if not modules: + # no log level properties + return False + + edge_id = properties.get('edge-id') + + for module, level in modules.items(): + 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)) + + except nsxv_exceptions.ResourceNotFound as e: + LOG.error(_LE("Edge %s not found"), edge_id) + except exceptions.NeutronException as e: + LOG.error(_LE("%s"), str(e)) + + # take ownership for properties + return True + + def change_edge_appliance_size(properties): size = properties.get('size') if size not in nsxv_constants.ALLOWED_EDGE_SIZES: @@ -320,10 +425,14 @@ def nsx_update_edge(resource, event, trigger, **kwargs): "attribute to update. Add --property edge-id= " "and --property highavailability= or " "--property size= or --property appliances=True. " - "For syslog, add --property syslog-server=|none and " + "\nFor syslog, add --property syslog-server=|none and " "(optional) --property syslog-server2= and/or " "(optional) --property syslog-proto=[tcp/udp] " - "For edge reservations, add " + "\nFor log levels, add --property [routing|dhcp|dns|" + "highavailability|loadbalancer]-log-level=" + "[debug|info|warning|error]. To set log level for all " + "modules, add --property log-level= " + "\nFor edge reservations, add " "--property resource=cpu|memory and " "(optional) --property limit= and/or " "(optional) --property shares= and/or " @@ -353,6 +462,8 @@ def nsx_update_edge(resource, event, trigger, **kwargs): change_edge_syslog(properties) elif properties.get('resource'): change_edge_appliance_reservations(properties) + elif change_edge_loglevel(properties): + pass else: # no attribute was specified LOG.error(usage_msg) diff --git a/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py b/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py index daf459e00f..c770b91e2d 100644 --- a/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py +++ b/vmware_nsx/tests/unit/nsx_v/vshield/fake_vcns.py @@ -1193,6 +1193,13 @@ class FakeVcns(object): response = '' return (header, response) + def update_edge_config_with_modifier(self, edge_id, module, modifier): + header = { + 'status': 204 + } + response = '' + return (header, response) + def change_edge_appliance_size(self, edge_id, size): header = { 'status': 204