Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Module nxos logging fixes #52883

Merged
merged 3 commits into from
Mar 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 19 additions & 13 deletions lib/ansible/module_utils/network/nxos/nxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,14 +301,16 @@ def _request_builder(self, commands, output, version='1.0', chunk='0', sid=None)
if isinstance(commands, (list, set, tuple)):
commands = ' ;'.join(commands)

msg = {
'version': version,
'type': command_type,
'chunk': chunk,
'sid': sid,
'input': commands,
'output_format': 'json'
}
# Order should not matter but some versions of NX-OS software fail
# to process the payload properly if 'input' gets serialized before
# 'type' and the payload of 'input' contains the word 'type'.
msg = collections.OrderedDict()
msg['version'] = version
msg['type'] = command_type
msg['chunk'] = chunk
msg['sid'] = sid
msg['input'] = commands
msg['output_format'] = 'json'

return dict(ins_api=msg)

Expand Down Expand Up @@ -448,7 +450,6 @@ def load_config(self, commands, return_error=False, opts=None, replace=None):
commands = 'config replace {0}'.format(replace)

commands = to_list(commands)

msg, msg_timestamps = self.send_request(commands, output='config', check_status=True,
return_error=return_error, opts=opts)
if return_error:
Expand Down Expand Up @@ -660,13 +661,18 @@ def check_edit_config_capability(self, candidate=None, commit=True, replace=None
raise ValueError("commit comment is not supported")

def read_module_context(self, module_key):
if self._module_context.get(module_key):
return self._module_context[module_key]
try:
module_context = self._connection.read_module_context(module_key)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

return None
return module_context

def save_module_context(self, module_key, module_context):
self._module_context[module_key] = module_context
try:
self._connection.save_module_context(module_key, module_context)
except ConnectionError as exc:
self._module.fail_json(msg=to_text(exc, errors='surrogate_then_replace'))

return None

Expand Down
41 changes: 35 additions & 6 deletions lib/ansible/modules/network/nxos/nxos_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@
purge:
description:
- Remove any switch logging configuration that does not match what has been configured
Not supported for ansible_connection local.
All nxos_logging tasks must use the same ansible_connection type.

type: bool
default: no
version_added: '2.8'
Expand Down Expand Up @@ -182,6 +185,7 @@
from ansible.module_utils.network.nxos.nxos import nxos_argument_spec, check_args, normalize_interface
from ansible.module_utils.basic import AnsibleModule


STATIC_CLI = {'link-enable': 'logging event link-status enable',
'link-default': 'logging event link-status default',
'trunk-enable': 'logging event trunk-status enable',
Expand All @@ -207,7 +211,7 @@
DEST_GROUP = ['console', 'logfile', 'module', 'monitor', 'server']


def map_obj_to_commands(updates):
def map_obj_to_commands(module, updates):
commands = list()
want, have = updates

Expand Down Expand Up @@ -295,8 +299,9 @@ def map_obj_to_commands(updates):
commands.append('logging level {0} {1}'.format(
w['facility'], STATIC_CLI[w['facility_link_status']]))
else:
commands.append('logging level {0} {1}'.format(w['facility'],
w['facility_level']))
if not match_facility_default(module, w['facility'], w['facility_level']):
commands.append('logging level {0} {1}'.format(w['facility'],
w['facility_level']))

if w['interface']:
commands.append('logging source-interface {0} {1}'.format(*split_interface(w['interface'])))
Expand All @@ -313,6 +318,30 @@ def map_obj_to_commands(updates):
return commands


def match_facility_default(module, facility, want_level):
''' Check wanted facility to see if it matches current device default '''

matches_default = False
# Sample output from show logging level command
# Facility Default Severity Current Session Severity
# -------- ---------------- ------------------------
# bfd 5 5
#
# 0(emergencies) 1(alerts) 2(critical)
# 3(errors) 4(warnings) 5(notifications)
# 6(information) 7(debugging)

regexl = r'\S+\s+(\d+)\s+(\d+)'
cmd = {'command': 'show logging level {0}'.format(facility), 'output': 'text'}
facility_data = run_commands(module, cmd)
for line in facility_data[0].split('\n'):
mo = re.search(regexl, line)
if mo and int(mo.group(1)) == int(want_level) and int(mo.group(2)) == int(want_level):
matches_default = True

return matches_default


def split_interface(interface):
match = re.search(r'(\D+)(\S*)', interface, re.M)
if match:
Expand Down Expand Up @@ -719,7 +748,7 @@ def main():
timestamp=dict(choices=['microseconds', 'milliseconds', 'seconds']),
state=dict(default='present', choices=['present', 'absent']),
aggregate=dict(type='list'),
purge=dict(default=False, type='bool')
purge=dict(default=False, type='bool'),
)

argument_spec.update(nxos_argument_spec)
Expand All @@ -742,7 +771,7 @@ def main():
merged_wants = merge_wants(read_module_context(module), want)
have = map_config_to_obj(module)

commands = map_obj_to_commands((want, have))
commands = map_obj_to_commands(module, (want, have))
result['commands'] = commands

if commands:
Expand All @@ -753,7 +782,7 @@ def main():
save_module_context(module, merged_wants)

if module.params.get('purge'):
pcommands = map_obj_to_commands((outliers(have, merged_wants), have))
pcommands = map_obj_to_commands(module, (outliers(have, merged_wants), have))
if pcommands:
if not module.check_mode:
load_config(module, pcommands)
Expand Down
32 changes: 24 additions & 8 deletions lib/ansible/plugins/httpapi/nxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import json
import re
import collections

from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
Expand All @@ -36,6 +37,18 @@ class HttpApi(HttpApiBase):
def __init__(self, *args, **kwargs):
super(HttpApi, self).__init__(*args, **kwargs)
self._device_info = None
self._module_context = {}

def read_module_context(self, module_key):
if self._module_context.get(module_key):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simply return self._module_context.get(module_key) will do the trick!

return self._module_context[module_key]

return None

def save_module_context(self, module_key, module_context):
self._module_context[module_key] = module_context

return None

def send_request(self, data, **message_kwargs):
output = None
Expand Down Expand Up @@ -201,12 +214,15 @@ def request_builder(commands, output, version='1.0', chunk='0', sid=None):
if isinstance(commands, (list, set, tuple)):
commands = ' ;'.join(commands)

msg = {
'version': version,
'type': command_type,
'chunk': chunk,
'sid': sid,
'input': commands,
'output_format': 'json'
}
# Order should not matter but some versions of NX-OS software fail
# to process the payload properly if 'input' gets serialized before
# 'type' and the payload of 'input' contains the word 'type'.
msg = collections.OrderedDict()
msg['version'] = version
msg['type'] = command_type
msg['chunk'] = chunk
msg['sid'] = sid
msg['input'] = commands
msg['output_format'] = 'json'

return json.dumps(dict(ins_api=msg))