From ed5a0f2d9ca757a77bdf9f7d0915225f028ef012 Mon Sep 17 00:00:00 2001 From: Nilashish Chakraborty Date: Thu, 5 Jul 2018 12:17:14 +0530 Subject: [PATCH] nxos_logging new feature - remote logging (#41237) * Added feature - Remote Logging + More tests * Fixed Shippable Errors * Fixes - new feature version added error --- .../modules/network/nxos/nxos_logging.py | 87 +++++++++++++++---- .../nxos_logging/tests/common/basic.yaml | 23 +++++ 2 files changed, 93 insertions(+), 17 deletions(-) diff --git a/lib/ansible/modules/network/nxos/nxos_logging.py b/lib/ansible/modules/network/nxos/nxos_logging.py index e20bd7c0d4f..b56c4e2e9b1 100644 --- a/lib/ansible/modules/network/nxos/nxos_logging.py +++ b/lib/ansible/modules/network/nxos/nxos_logging.py @@ -36,7 +36,11 @@ options: dest: description: - Destination of the logs. - choices: ['console', 'logfile', 'module', 'monitor'] + choices: ['console', 'logfile', 'module', 'monitor', 'server'] + remote_server: + description: + - Hostname or IP Address for remote logging (when dest is 'server'). + version_added: '2.7' name: description: - If value of C(dest) is I(logfile) it indicates file-name. @@ -102,12 +106,13 @@ commands: import re + from ansible.module_utils.network.nxos.nxos import get_config, load_config from ansible.module_utils.network.nxos.nxos import nxos_argument_spec, check_args from ansible.module_utils.basic import AnsibleModule -DEST_GROUP = ['console', 'logfile', 'module', 'monitor'] +DEST_GROUP = ['console', 'logfile', 'module', 'monitor', 'server'] def map_obj_to_commands(updates, module): @@ -115,17 +120,13 @@ def map_obj_to_commands(updates, module): want, have = updates for w in want: - dest = w['dest'] - name = w['name'] - facility = w['facility'] - dest_level = w['dest_level'] - facility_level = w['facility_level'] state = w['state'] del w['state'] if state == 'absent' and w in have: if w['facility'] is not None: - commands.append('no logging level {}'.format(w['facility'])) + if not w['dest']: + commands.append('no logging level {}'.format(w['facility'])) if w['name'] is not None: commands.append('no logging logfile') @@ -133,18 +134,38 @@ def map_obj_to_commands(updates, module): if w['dest'] in ('console', 'module', 'monitor'): commands.append('no logging {}'.format(w['dest'])) + if w['dest'] == 'server': + commands.append('no logging server {}'.format(w['remote_server'])) + if state == 'present' and w not in have: if w['facility'] is None: - if w['dest'] is not None: - if w['dest'] != 'logfile': + if w['dest']: + if w['dest'] not in ('logfile', 'server'): commands.append('logging {} {}'.format(w['dest'], w['dest_level'])) + elif w['dest'] == 'logfile': commands.append('logging logfile {} {}'.format(w['name'], w['dest_level'])) + + elif w['dest'] == 'server': + if w['dest_level']: + commands.append('logging server {0} {1}'.format( + w['remote_server'], w['dest_level'])) + else: + commands.append('logging server {0}'.format(w['remote_server'])) else: pass - if w['facility'] is not None: - commands.append('logging level {} {}'.format(w['facility'], w['facility_level'])) + if w['facility']: + if w['dest'] == 'server': + if w['dest_level']: + commands.append('logging server {0} {1} facility {2}'.format( + w['remote_server'], w['dest_level'], w['facility'])) + else: + commands.append('logging server {0} facility {1}'.format(w['remote_server'], + w['facility'])) + else: + commands.append('logging level {} {}'.format(w['facility'], + w['facility_level'])) return commands @@ -163,6 +184,17 @@ def parse_name(line, dest): return name +def parse_remote_server(line, dest): + remote_server = None + + if dest and dest == 'server': + match = re.search(r'logging server (\S+)', line, re.M) + if match: + remote_server = match.group(1) + + return remote_server + + def parse_dest_level(line, dest, name): dest_level = None @@ -180,6 +212,11 @@ def parse_dest_level(line, dest, name): match = re.search(r'logging logfile {} (\S+)'.format(name), line, re.M) if match: dest_level = parse_match(match) + + elif dest == 'server': + match = re.search(r'logging server (?:\S+) (\d+)', line, re.M) + if match: + dest_level = parse_match(match) else: match = re.search(r'logging {} (\S+)'.format(dest), line, re.M) if match: @@ -199,6 +236,16 @@ def parse_facility_level(line, facility): return facility_level +def parse_facility(line): + facility = None + + match = re.search(r'logging server (?:\S+) (?:\d+) (?:\S+) (?:\S+) (?:\S+) (\S+)', line, re.M) + if match: + facility = match.group(1) + + return facility + + def map_config_to_obj(module): obj = [] @@ -212,6 +259,9 @@ def map_config_to_obj(module): dest = match.group(1) facility = None + if dest == 'server': + facility = parse_facility(line) + elif match.group(1) == 'level': match_facility = re.search(r'logging level (\S+)', line, re.M) facility = match_facility.group(1) @@ -222,6 +272,7 @@ def map_config_to_obj(module): facility = None obj.append({'dest': dest, + 'remote_server': parse_remote_server(line, dest), 'name': parse_name(line, dest), 'facility': facility, 'dest_level': parse_dest_level(line, dest, parse_name(line, dest)), @@ -235,11 +286,11 @@ def map_params_to_obj(module): if 'aggregate' in module.params and module.params['aggregate']: args = {'dest': '', + 'remote_server': '', 'name': '', 'facility': '', 'dest_level': '', - 'facility_level': '' - } + 'facility_level': ''} for c in module.params['aggregate']: d = c.copy() @@ -271,13 +322,13 @@ def map_params_to_obj(module): obj.append({ 'dest': module.params['dest'], + 'remote_server': module.params['remote_server'], 'name': module.params['name'], 'facility': module.params['facility'], 'dest_level': dest_level, 'facility_level': facility_level, 'state': module.params['state'] }) - return obj @@ -288,6 +339,7 @@ def main(): dest=dict(choices=DEST_GROUP), name=dict(), facility=dict(), + remote_server=dict(), dest_level=dict(type='int', aliases=['level']), facility_level=dict(type='int'), state=dict(default='present', choices=['present', 'absent']), @@ -296,11 +348,11 @@ def main(): argument_spec.update(nxos_argument_spec) - required_if = [('dest', 'logfile', ['name'])] + required_if = [('dest', 'logfile', ['name']), + ('dest', 'server', ['remote_server'])] module = AnsibleModule(argument_spec=argument_spec, required_if=required_if, - required_together=[['facility', 'facility_level']], supports_check_mode=True) warnings = list() @@ -323,5 +375,6 @@ def main(): module.exit_json(**result) + if __name__ == '__main__': main() diff --git a/test/integration/targets/nxos_logging/tests/common/basic.yaml b/test/integration/targets/nxos_logging/tests/common/basic.yaml index b00d492dca3..de0d8995e41 100644 --- a/test/integration/targets/nxos_logging/tests/common/basic.yaml +++ b/test/integration/targets/nxos_logging/tests/common/basic.yaml @@ -98,6 +98,27 @@ - assert: *false +- name: Configure Remote Logging + nxos_logging: &rlog + dest: server + remote_server: test-syslogserver.com + facility: auth + dest_level: 1 + state: present + provider: "{{ connection }}" + register: result + +- assert: + that: + - 'result.changed == true' + - '"logging server test-syslogserver.com 1 facility auth" in result.commands' + +- name: Configure Remote Logging (idempotent) + nxos_logging: *rlog + register: result + +- assert: *false + - name: remove logging as collection tearDown nxos_logging: &agg aggregate: @@ -106,6 +127,7 @@ - { dest: monitor, dest_level: 3 } - { dest: logfile, dest_level: 1, name: test } - { facility: daemon, facility_level: 4 } + - { dest: server, remote_server: test-syslogserver.com, facility: auth, dest_level: 1 } provider: "{{ connection }}" state: absent register: result @@ -117,6 +139,7 @@ - '"no logging level daemon" in result.commands' - '"no logging monitor" in result.commands' - '"no logging module" in result.commands' + - '"no logging server test-syslogserver.com" in result.commands' - name: remove aggregate logging (idempotent) nxos_logging: *agg