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

stable-2.5 nxos bugfix cherry-pick #38372

Merged
merged 8 commits into from
Apr 6, 2018
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
6 changes: 6 additions & 0 deletions changelogs/fragments/nxos_bugfixes.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ bugfixes:
- nxos_vrf_af - Fix nxos_vrf_af issues (https://github.com/ansible/ansible/pull/37211)
- nxos_udld - Fix nxos_udld issues (https://github.com/ansible/ansible/pull/37418)
- nxos_vlan - Fix nxos_vlan issues (https://github.com/ansible/ansible/pull/38008)
- nxos_vlan - nxos_vlan purge (https://github.com/ansible/ansible/pull/38202)
- nxos_aaa_server - Fix nxos_aaa_server (https://github.com/ansible/ansible/pull/38117)
- nxos_aaa_server_host - Fix nxos_aaa_server_host (https://github.com/ansible/ansible/pull/38188)
- nxos_acl - Fix nxos_acl (https://github.com/ansible/ansible/pull/38283)
- nxos_static_route - Fix nxos_static_route (https://github.com/ansible/ansible/pull/37614)
- nxos_acl_interface test - Fix nxos_acl_interface test (https://github.com/ansible/ansible/pull/38230)
55 changes: 26 additions & 29 deletions lib/ansible/modules/network/nxos/nxos_aaa_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
stored as encrypted (type 7).
- Changes to the global AAA server key with encrypt_type=0
are not idempotent.
- If global AAA server key is not found, it's shown as "unknown"
- state=default will set the supplied parameters to their default values.
The parameters that you want to default must also be set to default.
If global_key=default, the global key will be removed.
Expand All @@ -51,9 +50,7 @@
choices: ['radius', 'tacacs']
global_key:
description:
- Global AAA shared secret.
required: false
default: null
- Global AAA shared secret or keyword 'default'.
encrypt_type:
description:
- The state of encryption applied to the entered global key.
Expand All @@ -64,18 +61,17 @@
deadtime:
description:
- Duration for which a non-reachable AAA server is skipped,
in minutes. Range is 1-1440. Device default is 0.
in minutes or keyword 'default.
Range is 1-1440. Device default is 0.
required: false
default: null
server_timeout:
description:
- Global AAA server timeout period, in seconds. Range is 1-60.
Device default is 5.
required: false
default: null
- Global AAA server timeout period, in seconds or keyword 'default.
Range is 1-60. Device default is 5.
directed_request:
description:
- Enables direct authentication requests to AAA server.
- Enables direct authentication requests to AAA server or keyword 'default'
Device default is disabled.
required: false
default: null
Expand Down Expand Up @@ -127,7 +123,14 @@
from ansible.module_utils.basic import AnsibleModule


def execute_show_command(command, module, command_type='cli_show'):
PARAM_TO_DEFAULT_KEYMAP = {
'server_timeout': '5',
'deadtime': '0',
'directed_request': 'disabled',
}


def execute_show_command(command, module):
command = {
'command': command,
'output': 'text',
Expand All @@ -153,8 +156,7 @@ def get_aaa_server_info(server_type, module):
global_key_command = 'show run | sec {0}'.format(server_type)
aaa_regex = r'.*{0}-server\skey\s\d\s+(?P<key>\S+).*'.format(server_type)

server_body = execute_show_command(
server_command, module, command_type='cli_show_ascii')[0]
server_body = execute_show_command(server_command, module)[0]

split_server = server_body.splitlines()

Expand All @@ -165,30 +167,25 @@ def get_aaa_server_info(server_type, module):
elif line.startswith('deadtime'):
aaa_server_info['deadtime'] = line.split(':')[1]

request_body = execute_show_command(
request_command, module, command_type='cli_show_ascii')[0]
aaa_server_info['directed_request'] = request_body.replace('\n', '')
request_body = execute_show_command(request_command, module)[0]

key_body = execute_show_command(
global_key_command, module, command_type='cli_show_ascii')[0]
if bool(request_body):
aaa_server_info['directed_request'] = request_body.replace('\n', '')
else:
aaa_server_info['directed_request'] = 'disabled'

key_body = execute_show_command(global_key_command, module)[0]

try:
match_global_key = re.match(aaa_regex, key_body, re.DOTALL)
group_key = match_global_key.groupdict()
aaa_server_info['global_key'] = group_key["key"].replace('\"', '')
except (AttributeError, TypeError):
aaa_server_info['global_key'] = 'unknown'
aaa_server_info['global_key'] = None

return aaa_server_info


def set_aaa_server_global_key(encrypt_type, key, server_type):
if not encrypt_type:
encrypt_type = ''
return '{0}-server key {1} {2}'.format(
server_type, encrypt_type, key)


def config_aaa_server(params, server_type):
cmds = []

Expand Down Expand Up @@ -226,13 +223,13 @@ def default_aaa_server(existing, params, server_type):
global_key = params.get('global_key')
existing_key = existing.get('global_key')

if deadtime is not None:
if deadtime is not None and existing.get('deadtime') != PARAM_TO_DEFAULT_KEYMAP['deadtime']:
cmds.append('no {0}-server deadtime 1'.format(server_type))

if server_timeout is not None:
if server_timeout is not None and existing.get('server_timeout') != PARAM_TO_DEFAULT_KEYMAP['server_timeout']:
cmds.append('no {0}-server timeout 1'.format(server_type))

if directed_request is not None:
if directed_request is not None and existing.get('directed_request') != PARAM_TO_DEFAULT_KEYMAP['directed_request']:
cmds.append('no {0}-server directed-request'.format(server_type))

if global_key is not None and existing_key is not None:
Expand Down
163 changes: 73 additions & 90 deletions lib/ansible/modules/network/nxos/nxos_aaa_server_host.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
author: Jason Edelman (@jedelman8)
notes:
- Tested against NXOSv 7.3.(0)D1(1) on VIRL
- Changes to the AAA server host key (shared secret) are not idempotent.
- Changes to the host key (shared secret) are not idempotent for type 0.
- If C(state=absent) removes the whole host configuration.
options:
server_type:
Expand All @@ -47,41 +47,29 @@
required: true
key:
description:
- Shared secret for the specified host.
required: false
default: null
- Shared secret for the specified host or keyword 'default'.
encrypt_type:
description:
- The state of encryption applied to the entered key.
O for clear text, 7 for encrypted. Type-6 encryption is
not supported.
required: false
default: null
choices: ['0', '7']
host_timeout:
description:
- Timeout period for specified host, in seconds. Range is 1-60.
required: false
default: null
- Timeout period for specified host, in seconds or keyword 'default.
Range is 1-60.
auth_port:
description:
- Alternate UDP port for RADIUS authentication.
required: false
default: null
- Alternate UDP port for RADIUS authentication or keyword 'default'.
acct_port:
description:
- Alternate UDP port for RADIUS accounting.
required: false
default: null
- Alternate UDP port for RADIUS accounting or keyword 'default'.
tacacs_port:
description:
- Alternate TCP port TACACS Server.
required: false
default: null
- Alternate TCP port TACACS Server or keyword 'default'.
state:
description:
- Manage the state of the resource.
required: false
default: present
choices: ['present','absent']
'''
Expand Down Expand Up @@ -160,13 +148,11 @@
from ansible.module_utils.basic import AnsibleModule


def execute_show_command(command, module, command_type='cli_show'):
def execute_show_command(command, module):
device_info = get_capabilities(module)
network_api = device_info.get('network_api', 'nxapi')

if network_api == 'cliconf':
if 'show run' not in command:
command += ' | json'
cmds = [command]
body = run_commands(module, cmds)
elif network_api == 'nxapi':
Expand All @@ -186,40 +172,36 @@ def flatten_list(command_lists):
return flat_command_list


def _match_dict(match_list, key_map):
no_blanks = []
match_dict = {}

for match_set in match_list:
match_set = tuple(v for v in match_set if v)
no_blanks.append(match_set)

for info in no_blanks:
words = info[0].strip().split()
length = len(words)
alt_key = key_map.get(words[0])
first = alt_key or words[0]
last = words[length - 1]
match_dict[first] = last.replace('\"', '')

return match_dict


def get_aaa_host_info(module, server_type, address):
aaa_host_info = {}
command = 'show run | inc {0}-server.host.{1}'.format(server_type, address)

body = execute_show_command(command, module, command_type='cli_show_ascii')

if body[0]:
body = execute_show_command(command, module)[0]
if body:
try:
pattern = (r'(acct-port \d+)|(timeout \d+)|(auth-port \d+)|'
r'(key 7 "\w+")|( port \d+)')
raw_match = re.findall(pattern, body[0])
aaa_host_info = _match_dict(raw_match, {'acct-port': 'acct_port',
'auth-port': 'auth_port',
'port': 'tacacs_port',
'timeout': 'host_timeout'})
if 'radius' in body:
pattern = (r'\S+ host \S+(?:\s+key 7\s+(\S+))?(?:\s+auth-port (\d+))?'
r'(?:\s+acct-port (\d+))?(?:\s+authentication)?'
r'(?:\s+accounting)?(?:\s+timeout (\d+))?')
match = re.search(pattern, body)
aaa_host_info['key'] = match.group(1)
if aaa_host_info['key']:
aaa_host_info['key'] = aaa_host_info['key'].replace('"', '')
aaa_host_info['encrypt_type'] = '7'
aaa_host_info['auth_port'] = match.group(2)
aaa_host_info['acct_port'] = match.group(3)
aaa_host_info['host_timeout'] = match.group(4)
elif 'tacacs' in body:
pattern = (r'\S+ host \S+(?:\s+key 7\s+(\S+))?(?:\s+port (\d+))?'
r'(?:\s+timeout (\d+))?')
match = re.search(pattern, body)
aaa_host_info['key'] = match.group(1)
if aaa_host_info['key']:
aaa_host_info['key'] = aaa_host_info['key'].replace('"', '')
aaa_host_info['encrypt_type'] = '7'
aaa_host_info['tacacs_port'] = match.group(2)
aaa_host_info['host_timeout'] = match.group(3)

aaa_host_info['server_type'] = server_type
aaa_host_info['address'] = address
except TypeError:
Expand All @@ -230,35 +212,41 @@ def get_aaa_host_info(module, server_type, address):
return aaa_host_info


def config_aaa_host(server_type, address, params, clear=False):
def config_aaa_host(server_type, address, params, existing):
cmds = []

if clear:
cmds.append('no {0}-server host {1}'.format(server_type, address))

cmd_str = '{0}-server host {1}'.format(server_type, address)
cmd_no_str = 'no ' + cmd_str

key = params.get('key')
enc_type = params.get('encrypt_type', '')
host_timeout = params.get('host_timeout')
auth_port = params.get('auth_port')
acct_port = params.get('acct_port')
port = params.get('tacacs_port')

if auth_port:
cmd_str += ' auth-port {0}'.format(auth_port)
if acct_port:
cmd_str += ' acct-port {0}'.format(acct_port)
if port:
cmd_str += ' port {0}'.format(port)
if host_timeout:
cmd_str += ' timeout {0}'.format(host_timeout)

defval = False
nondef = False

if key:
cmds.append('{0}-server host {1} key {2} {3}'.format(server_type,
address,
enc_type, key))
if key != 'default':
cmds.append(cmd_str + ' key {0} {1}'.format(enc_type, key))
else:
cmds.append(cmd_no_str + ' key 7 {0}'.format(existing.get('key')))

locdict = {'auth_port': 'auth-port', 'acct_port': 'acct-port',
'tacacs_port': 'port', 'host_timeout': 'timeout'}

# platform CLI needs the keywords in the following order
for key in ['auth_port', 'acct_port', 'tacacs_port', 'host_timeout']:
item = params.get(key)
if item:
if item != 'default':
cmd_str += ' {0} {1}'.format(locdict.get(key), item)
nondef = True
else:
cmd_no_str += ' {0} 1'.format(locdict.get(key))
defval = True
if defval:
cmds.append(cmd_no_str)
if nondef or not existing:
cmds.append(cmd_str)

cmds.append(cmd_str)
return cmds


Expand Down Expand Up @@ -315,24 +303,19 @@ def main():
end_state = existing

commands = []
delta = {}
if state == 'present':
host_timeout = proposed.get('host_timeout')
if host_timeout:
try:
if int(host_timeout) < 1 or int(host_timeout) > 60:
raise ValueError
except ValueError:
module.fail_json(
msg='host_timeout must be an integer between 1 and 60')

delta = dict(
set(proposed.items()).difference(existing.items()))
if delta:
union = existing.copy()
union.update(delta)
command = config_aaa_host(server_type, address, union)
if command:
commands.append(command)
if not existing:
delta = proposed
else:
for key, value in proposed.items():
if value != existing.get(key):
if value != 'default' or existing.get(key):
delta[key] = value

command = config_aaa_host(server_type, address, delta, existing)
if command:
commands.append(command)

elif state == 'absent':
intersect = dict(
Expand Down