fix nxos_aaa_server_host issues (#38188)
This commit is contained in:
parent
35b7b608bf
commit
24cc6b80bd
3 changed files with 188 additions and 87 deletions
|
@ -33,7 +33,7 @@ description:
|
||||||
author: Jason Edelman (@jedelman8)
|
author: Jason Edelman (@jedelman8)
|
||||||
notes:
|
notes:
|
||||||
- Tested against NXOSv 7.3.(0)D1(1) on VIRL
|
- 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.
|
- If C(state=absent) removes the whole host configuration.
|
||||||
options:
|
options:
|
||||||
server_type:
|
server_type:
|
||||||
|
@ -47,7 +47,7 @@ options:
|
||||||
required: true
|
required: true
|
||||||
key:
|
key:
|
||||||
description:
|
description:
|
||||||
- Shared secret for the specified host.
|
- Shared secret for the specified host or keyword 'default'.
|
||||||
encrypt_type:
|
encrypt_type:
|
||||||
description:
|
description:
|
||||||
- The state of encryption applied to the entered key.
|
- The state of encryption applied to the entered key.
|
||||||
|
@ -56,16 +56,17 @@ options:
|
||||||
choices: ['0', '7']
|
choices: ['0', '7']
|
||||||
host_timeout:
|
host_timeout:
|
||||||
description:
|
description:
|
||||||
- Timeout period for specified host, in seconds. Range is 1-60.
|
- Timeout period for specified host, in seconds or keyword 'default.
|
||||||
|
Range is 1-60.
|
||||||
auth_port:
|
auth_port:
|
||||||
description:
|
description:
|
||||||
- Alternate UDP port for RADIUS authentication.
|
- Alternate UDP port for RADIUS authentication or keyword 'default'.
|
||||||
acct_port:
|
acct_port:
|
||||||
description:
|
description:
|
||||||
- Alternate UDP port for RADIUS accounting.
|
- Alternate UDP port for RADIUS accounting or keyword 'default'.
|
||||||
tacacs_port:
|
tacacs_port:
|
||||||
description:
|
description:
|
||||||
- Alternate TCP port TACACS Server.
|
- Alternate TCP port TACACS Server or keyword 'default'.
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- Manage the state of the resource.
|
- Manage the state of the resource.
|
||||||
|
@ -147,13 +148,11 @@ from ansible.module_utils.network.nxos.nxos import get_capabilities, nxos_argume
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
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)
|
device_info = get_capabilities(module)
|
||||||
network_api = device_info.get('network_api', 'nxapi')
|
network_api = device_info.get('network_api', 'nxapi')
|
||||||
|
|
||||||
if network_api == 'cliconf':
|
if network_api == 'cliconf':
|
||||||
if 'show run' not in command:
|
|
||||||
command += ' | json'
|
|
||||||
cmds = [command]
|
cmds = [command]
|
||||||
body = run_commands(module, cmds)
|
body = run_commands(module, cmds)
|
||||||
elif network_api == 'nxapi':
|
elif network_api == 'nxapi':
|
||||||
|
@ -173,40 +172,36 @@ def flatten_list(command_lists):
|
||||||
return flat_command_list
|
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):
|
def get_aaa_host_info(module, server_type, address):
|
||||||
aaa_host_info = {}
|
aaa_host_info = {}
|
||||||
command = 'show run | inc {0}-server.host.{1}'.format(server_type, address)
|
command = 'show run | inc {0}-server.host.{1}'.format(server_type, address)
|
||||||
|
|
||||||
body = execute_show_command(command, module, command_type='cli_show_ascii')
|
body = execute_show_command(command, module)[0]
|
||||||
|
if body:
|
||||||
if body[0]:
|
|
||||||
try:
|
try:
|
||||||
pattern = (r'(acct-port \d+)|(timeout \d+)|(auth-port \d+)|'
|
if 'radius' in body:
|
||||||
r'(key 7 "\w+")|( port \d+)')
|
pattern = (r'\S+ host \S+(?:\s+key 7\s+(\S+))?(?:\s+auth-port (\d+))?'
|
||||||
raw_match = re.findall(pattern, body[0])
|
r'(?:\s+acct-port (\d+))?(?:\s+authentication)?'
|
||||||
aaa_host_info = _match_dict(raw_match, {'acct-port': 'acct_port',
|
r'(?:\s+accounting)?(?:\s+timeout (\d+))?')
|
||||||
'auth-port': 'auth_port',
|
match = re.search(pattern, body)
|
||||||
'port': 'tacacs_port',
|
aaa_host_info['key'] = match.group(1)
|
||||||
'timeout': 'host_timeout'})
|
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['server_type'] = server_type
|
||||||
aaa_host_info['address'] = address
|
aaa_host_info['address'] = address
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -217,35 +212,41 @@ def get_aaa_host_info(module, server_type, address):
|
||||||
return aaa_host_info
|
return aaa_host_info
|
||||||
|
|
||||||
|
|
||||||
def config_aaa_host(server_type, address, params, clear=False):
|
def config_aaa_host(server_type, address, params, existing):
|
||||||
cmds = []
|
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_str = '{0}-server host {1}'.format(server_type, address)
|
||||||
|
cmd_no_str = 'no ' + cmd_str
|
||||||
|
|
||||||
key = params.get('key')
|
key = params.get('key')
|
||||||
enc_type = params.get('encrypt_type', '')
|
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:
|
defval = False
|
||||||
cmd_str += ' auth-port {0}'.format(auth_port)
|
nondef = False
|
||||||
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)
|
|
||||||
if key:
|
if key:
|
||||||
cmds.append('{0}-server host {1} key {2} {3}'.format(server_type,
|
if key != 'default':
|
||||||
address,
|
cmds.append(cmd_str + ' key {0} {1}'.format(enc_type, key))
|
||||||
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
|
return cmds
|
||||||
|
|
||||||
|
|
||||||
|
@ -302,24 +303,19 @@ def main():
|
||||||
end_state = existing
|
end_state = existing
|
||||||
|
|
||||||
commands = []
|
commands = []
|
||||||
|
delta = {}
|
||||||
if state == 'present':
|
if state == 'present':
|
||||||
host_timeout = proposed.get('host_timeout')
|
if not existing:
|
||||||
if host_timeout:
|
delta = proposed
|
||||||
try:
|
else:
|
||||||
if int(host_timeout) < 1 or int(host_timeout) > 60:
|
for key, value in proposed.items():
|
||||||
raise ValueError
|
if value != existing.get(key):
|
||||||
except ValueError:
|
if value != 'default' or existing.get(key):
|
||||||
module.fail_json(
|
delta[key] = value
|
||||||
msg='host_timeout must be an integer between 1 and 60')
|
|
||||||
|
|
||||||
delta = dict(
|
command = config_aaa_host(server_type, address, delta, existing)
|
||||||
set(proposed.items()).difference(existing.items()))
|
if command:
|
||||||
if delta:
|
commands.append(command)
|
||||||
union = existing.copy()
|
|
||||||
union.update(delta)
|
|
||||||
command = config_aaa_host(server_type, address, union)
|
|
||||||
if command:
|
|
||||||
commands.append(command)
|
|
||||||
|
|
||||||
elif state == 'absent':
|
elif state == 'absent':
|
||||||
intersect = dict(
|
intersect = dict(
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *false
|
- assert: *false
|
||||||
|
|
||||||
- name: "Configure radius server non defaults"
|
- name: "Configure radius server non defaults"
|
||||||
nxos_aaa_server_host: &configure_radius_non_default
|
nxos_aaa_server_host: &configure_radius_non_default
|
||||||
server_type: radius
|
server_type: radius
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
state: present
|
state: present
|
||||||
provider: "{{ connection }}"
|
provider: "{{ connection }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
- name: "Check Idempotence"
|
- name: "Check Idempotence"
|
||||||
|
@ -63,25 +63,38 @@
|
||||||
|
|
||||||
- assert: *false
|
- assert: *false
|
||||||
|
|
||||||
- name: "Remove radius server configuration"
|
- name: "Configure some defaults on radius server"
|
||||||
nxos_aaa_server_host: *remove
|
nxos_aaa_server_host: &configure_some_radius_default
|
||||||
|
server_type: radius
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
auth_port: 1000
|
||||||
|
acct_port: default
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_some_radius_default
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
- name: "Configure radius server with clear text pwd"
|
- name: "Configure radius server with clear text pwd"
|
||||||
nxos_aaa_server_host: &configure_radius_clear_text
|
nxos_aaa_server_host: &configure_radius_clear_text
|
||||||
server_type: radius
|
server_type: radius
|
||||||
address: 8.8.8.8
|
address: 8.8.8.8
|
||||||
host_timeout: 25
|
host_timeout: 25
|
||||||
auth_port: 2083
|
auth_port: default
|
||||||
acct_port: 2084
|
acct_port: 2084
|
||||||
encrypt_type: 0
|
encrypt_type: 0
|
||||||
key: hello
|
key: hello
|
||||||
state: present
|
state: present
|
||||||
provider: "{{ connection }}"
|
provider: "{{ connection }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
- name: "Check NOT Idempotent"
|
- name: "Check NOT Idempotent"
|
||||||
|
@ -115,8 +128,49 @@
|
||||||
nxos_aaa_server_host: *configure_radius_type7
|
nxos_aaa_server_host: *configure_radius_type7
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
|
- name: "Configure radius server with default key"
|
||||||
|
nxos_aaa_server_host: &configure_radius_defkey
|
||||||
|
server_type: radius
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
auth_port: 1000
|
||||||
|
acct_port: default
|
||||||
|
encrypt_type: 7
|
||||||
|
key: default
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_radius_defkey
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
|
- name: "Configure radius server with all def"
|
||||||
|
nxos_aaa_server_host: &configure_radius_alldef
|
||||||
|
server_type: radius
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
auth_port: default
|
||||||
|
acct_port: default
|
||||||
|
key: default
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_radius_alldef
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
rescue:
|
rescue:
|
||||||
|
|
||||||
- debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected"
|
- debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected"
|
||||||
|
@ -127,4 +181,4 @@
|
||||||
nxos_aaa_server_host: *remove
|
nxos_aaa_server_host: *remove
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- debug: msg="END connection={{ ansible_connection }} nxos_aaa_server_host radius.yaml sanity test"
|
- debug: msg="END connection={{ ansible_connection }} nxos_aaa_server_host radius.yaml sanity test"
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
state: present
|
state: present
|
||||||
provider: "{{ connection }}"
|
provider: "{{ connection }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
- name: "Check Idempotence"
|
- name: "Check Idempotence"
|
||||||
|
@ -69,18 +69,30 @@
|
||||||
|
|
||||||
- assert: *false
|
- assert: *false
|
||||||
|
|
||||||
- name: "Remove tacacs server configuration"
|
- name: "Configure some defaults on tacacs server"
|
||||||
nxos_aaa_server_host: *remove
|
nxos_aaa_server_host: &configure_some_tacacs_default
|
||||||
|
server_type: tacacs
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
tacacs_port: 100
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_some_tacacs_default
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
- name: "Configure tacacs server with clear text pwd"
|
- name: "Configure tacacs server with clear text pwd"
|
||||||
nxos_aaa_server_host: &configure_tacacs_clear_text
|
nxos_aaa_server_host: &configure_tacacs_clear_text
|
||||||
server_type: tacacs
|
server_type: tacacs
|
||||||
address: 8.8.8.8
|
address: 8.8.8.8
|
||||||
host_timeout: 25
|
host_timeout: 25
|
||||||
tacacs_port: 89
|
tacacs_port: default
|
||||||
encrypt_type: 0
|
encrypt_type: 0
|
||||||
key: hello
|
key: hello
|
||||||
state: present
|
state: present
|
||||||
|
@ -119,8 +131,47 @@
|
||||||
nxos_aaa_server_host: *configure_tacacs_type7
|
nxos_aaa_server_host: *configure_tacacs_type7
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
|
- name: "Configure tacacs server with default key"
|
||||||
|
nxos_aaa_server_host: &configure_tacacs_defkey
|
||||||
|
server_type: tacacs
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
tacacs_port: 89
|
||||||
|
encrypt_type: 7
|
||||||
|
key: default
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
- assert: *true
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_tacacs_defkey
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
|
- name: "Configure tacacs server with all def"
|
||||||
|
nxos_aaa_server_host: &configure_tacacs_alldef
|
||||||
|
server_type: tacacs
|
||||||
|
address: 8.8.8.8
|
||||||
|
host_timeout: default
|
||||||
|
tacacs_port: default
|
||||||
|
key: default
|
||||||
|
state: present
|
||||||
|
provider: "{{ connection }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *true
|
||||||
|
|
||||||
|
- name: "Check Idempotence"
|
||||||
|
nxos_aaa_server_host: *configure_tacacs_alldef
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert: *false
|
||||||
|
|
||||||
rescue:
|
rescue:
|
||||||
|
|
||||||
- debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected"
|
- debug: msg="connection={{ ansible_connection }} nxos_aaa_server_host failure detected"
|
||||||
|
@ -131,7 +182,7 @@
|
||||||
nxos_aaa_server_host: *remove
|
nxos_aaa_server_host: *remove
|
||||||
register: result
|
register: result
|
||||||
|
|
||||||
- name: "Enable feature tacacs+"
|
- name: "Disable feature tacacs+"
|
||||||
nxos_feature:
|
nxos_feature:
|
||||||
feature: tacacs+
|
feature: tacacs+
|
||||||
state: disabled
|
state: disabled
|
||||||
|
|
Loading…
Reference in a new issue