nxos and ios bugfix stable-2.5 (#39845)

* nxos_linkagg normalize interface (#39591)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit 3c35dd4f7f)

* use show run instead of section pipeline ios_l2_interface (#39658)

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
(cherry picked from commit dddcbb7198)

* add changelog

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>

* fix nxos_snmp_user issues (#39760)

* fix nxos_snmp_user issues

* shipppable fix

(cherry picked from commit e3bfbe5875)

* changelog

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>

* fix shippable

Signed-off-by: Trishna Guha <trishnaguha17@gmail.com>
pull/39852/head
Trishna Guha 7 years ago committed by GitHub
parent 54a229adb9
commit 079b7cb1fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,2 +1,3 @@
bugfixes: bugfixes:
- ios_l2_interface - fix removal of trunk vlans (https://github.com/ansible/ansible/pull/37389) - ios_l2_interface - fix removal of trunk vlans (https://github.com/ansible/ansible/pull/37389)
- ios_l2_interface - use show run instead of section pipeline ios_l2_interface (https://github.com/ansible/ansible/pull/39658)

@ -27,3 +27,5 @@ bugfixes:
- nxos_l2_interface - Add aggregate example in nxos_l2_interface module doc (https://github.com/ansible/ansible/pull/39275) - nxos_l2_interface - Add aggregate example in nxos_l2_interface module doc (https://github.com/ansible/ansible/pull/39275)
- nxos_snmp_host - Fix for nxos_snmp_host issues (https://github.com/ansible/ansible/pull/39642) - nxos_snmp_host - Fix for nxos_snmp_host issues (https://github.com/ansible/ansible/pull/39642)
- nxos_snmp_traps - Fix nxos_snmp_traps issues (https://github.com/ansible/ansible/pull/39444) - nxos_snmp_traps - Fix nxos_snmp_traps issues (https://github.com/ansible/ansible/pull/39444)
- nxos_linkagg - nxos_linkagg abbreviated form issue (https://github.com/ansible/ansible/pull/39591)
- nxos_snmp_user - Fix nxos_snmp_user (https://github.com/ansible/ansible/pull/39760)

@ -146,10 +146,9 @@ def is_switchport(name, module):
def interface_is_portchannel(name, module): def interface_is_portchannel(name, module):
if get_interface_type(name) == 'ethernet': if get_interface_type(name) == 'ethernet':
config = get_config(module, flags=[' | section interface']) config = run_commands(module, ['show run interface {0}'.format(name)])[0]
if 'channel group' in config: if any(c in config for c in ['channel group', 'channel-group']):
return True return True
return False return False

@ -138,6 +138,46 @@ from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network.common.utils import remove_default_spec from ansible.module_utils.network.common.utils import remove_default_spec
def normalize_interface(name):
"""Return the normalized interface name
"""
if not name:
return
def _get_number(name):
digits = ''
for char in name:
if char.isdigit() or char in '/.':
digits += char
return digits
if name.lower().startswith('et'):
if_type = 'Ethernet'
elif name.lower().startswith('vl'):
if_type = 'Vlan'
elif name.lower().startswith('lo'):
if_type = 'loopback'
elif name.lower().startswith('po'):
if_type = 'port-channel'
elif name.lower().startswith('nv'):
if_type = 'nve'
else:
if_type = None
number_list = name.split(' ')
if len(number_list) == 2:
number = number_list[-1].strip()
else:
number = _get_number(name)
if if_type:
proper_interface = if_type + number
else:
proper_interface = name
return proper_interface
def execute_show_command(command, module): 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')
@ -250,14 +290,20 @@ def map_params_to_obj(module):
d = item.copy() d = item.copy()
d['group'] = str(d['group']) d['group'] = str(d['group'])
d['min_links'] = str(d['min_links']) d['min_links'] = str(d['min_links'])
if d['members']:
d['members'] = [normalize_interface(i) for i in d['members']]
obj.append(d) obj.append(d)
else: else:
members = None
if module.params['members']:
members = [normalize_interface(i) for i in module.params['members']]
obj.append({ obj.append({
'group': str(module.params['group']), 'group': str(module.params['group']),
'mode': module.params['mode'], 'mode': module.params['mode'],
'min_links': str(module.params['min_links']), 'min_links': str(module.params['min_links']),
'members': module.params['members'], 'members': members,
'state': module.params['state'] 'state': module.params['state']
}) })
@ -296,10 +342,10 @@ def get_members(channel):
return list() return list()
if isinstance(interfaces, dict): if isinstance(interfaces, dict):
members.append(interfaces.get('port')) members.append(normalize_interface(interfaces.get('port')))
elif isinstance(interfaces, list): elif isinstance(interfaces, list):
for i in interfaces: for i in interfaces:
members.append(i.get('port')) members.append(normalize_interface(i.get('port')))
return members return members

@ -42,33 +42,34 @@ options:
group: group:
description: description:
- Group to which the user will belong to. - Group to which the user will belong to.
required: true If state = present, and the user is existing,
the group is added to the user. If the user
is not existing, user entry is created with this
group argument.
If state = absent, only the group is removed from the
user entry. However, to maintain backward compatibility,
if the existing user belongs to only one group, and if
group argument is same as the existing user's group,
then the user entry also is deleted.
authentication: authentication:
description: description:
- Authentication parameters for the user. - Authentication parameters for the user.
required: false
default: null
choices: ['md5', 'sha'] choices: ['md5', 'sha']
pwd: pwd:
description: description:
- Authentication password when using md5 or sha. - Authentication password when using md5 or sha.
required: false This is not idempotent
default: null
privacy: privacy:
description: description:
- Privacy password for the user. - Privacy password for the user.
required: false This is not idempotent
default: null
encrypt: encrypt:
description: description:
- Enables AES-128 bit encryption when using privacy password. - Enables AES-128 bit encryption when using privacy password.
required: false type: bool
default: null
choices: ['true','false']
state: state:
description: description:
- Manage the state of the resource. - Manage the state of the resource.
required: false
default: present default: present
choices: ['present','absent'] choices: ['present','absent']
''' '''
@ -157,8 +158,18 @@ def get_snmp_user(user, module):
privkey = 'priv' privkey = 'priv'
grpkey = 'group' grpkey = 'group'
resource_table = body[0][tablekey][rowkey] rt = body[0][tablekey][rowkey]
resource['user'] = str(resource_table['user']) # on some older platforms, all groups except the 1st one
# are in list elements by themselves and they are
# indexed by 'user'. This is due to a platform bug.
# Get first element if rt is a list due to the bug
# or if there is no bug, parse rt directly
if isinstance(rt, list):
resource_table = rt[0]
else:
resource_table = rt
resource['user'] = user
resource['authentication'] = str(resource_table[authkey]).strip() resource['authentication'] = str(resource_table[authkey]).strip()
encrypt = str(resource_table[privkey]).strip() encrypt = str(resource_table[privkey]).strip()
if encrypt.startswith('aes'): if encrypt.startswith('aes'):
@ -175,6 +186,15 @@ def get_snmp_user(user, module):
except TypeError: except TypeError:
groups.append(str(group_table[grpkey]).strip()) groups.append(str(group_table[grpkey]).strip())
# Now for the platform bug case, get the groups
if isinstance(rt, list):
# remove 1st element from the list as this is parsed already
rt.pop(0)
# iterate through other elements indexed by
# 'user' and add it to groups.
for each in rt:
groups.append(each['user'].strip())
resource['group'] = groups resource['group'] = groups
except (KeyError, AttributeError, IndexError, TypeError): except (KeyError, AttributeError, IndexError, TypeError):
@ -183,22 +203,23 @@ def get_snmp_user(user, module):
return resource return resource
def remove_snmp_user(user): def remove_snmp_user(user, group=None):
return ['no snmp-server user {0}'.format(user)] if group:
return ['no snmp-server user {0} {1}'.format(user, group)]
else:
return ['no snmp-server user {0}'.format(user)]
def config_snmp_user(proposed, user, reset, new): def config_snmp_user(proposed, user, reset):
if reset and not new: if reset:
commands = remove_snmp_user(user) commands = remove_snmp_user(user)
else: else:
commands = [] commands = []
group = proposed.get('group', None) if proposed.get('group'):
cmd = ''
if group:
cmd = 'snmp-server user {0} {group}'.format(user, **proposed) cmd = 'snmp-server user {0} {group}'.format(user, **proposed)
else:
cmd = 'snmp-server user {0}'.format(user)
auth = proposed.get('authentication', None) auth = proposed.get('authentication', None)
pwd = proposed.get('pwd', None) pwd = proposed.get('pwd', None)
@ -223,7 +244,7 @@ def config_snmp_user(proposed, user, reset, new):
def main(): def main():
argument_spec = dict( argument_spec = dict(
user=dict(required=True, type='str'), user=dict(required=True, type='str'),
group=dict(type='str', required=True), group=dict(type='str'),
pwd=dict(type='str'), pwd=dict(type='str'),
privacy=dict(type='str'), privacy=dict(type='str'),
authentication=dict(choices=['md5', 'sha']), authentication=dict(choices=['md5', 'sha']),
@ -260,19 +281,28 @@ def main():
existing = get_snmp_user(user, module) existing = get_snmp_user(user, module)
if existing: if state == 'present' and existing:
if group not in existing['group']: if group:
existing['group'] = None if group not in existing['group']:
existing['group'] = None
else:
existing['group'] = group
else: else:
existing['group'] = group existing['group'] = None
commands = [] commands = []
if state == 'absent' and existing: if state == 'absent' and existing:
commands.append(remove_snmp_user(user)) if group:
if group in existing['group']:
if len(existing['group']) == 1:
commands.append(remove_snmp_user(user))
else:
commands.append(remove_snmp_user(user, group))
else:
commands.append(remove_snmp_user(user))
elif state == 'present': elif state == 'present':
new = False
reset = False reset = False
args = dict(user=user, pwd=pwd, group=group, privacy=privacy, args = dict(user=user, pwd=pwd, group=group, privacy=privacy,
@ -282,7 +312,7 @@ def main():
if not existing: if not existing:
if encrypt: if encrypt:
proposed['encrypt'] = 'aes-128' proposed['encrypt'] = 'aes-128'
commands.append(config_snmp_user(proposed, user, reset, new)) commands.append(config_snmp_user(proposed, user, reset))
elif existing: elif existing:
if encrypt and not existing['encrypt'].startswith('aes'): if encrypt and not existing['encrypt'].startswith('aes'):
@ -294,14 +324,12 @@ def main():
if delta.get('pwd'): if delta.get('pwd'):
delta['authentication'] = authentication delta['authentication'] = authentication
if delta:
delta['group'] = group
if delta and encrypt: if delta and encrypt:
delta['encrypt'] = 'aes-128' delta['encrypt'] = 'aes-128'
command = config_snmp_user(delta, user, reset, new) if delta:
commands.append(command) command = config_snmp_user(delta, user, reset)
commands.append(command)
cmds = flatten_list(commands) cmds = flatten_list(commands)
if cmds: if cmds:

@ -3,41 +3,88 @@
- debug: msg="Using provider={{ connection.transport }}" - debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local" when: ansible_connection == "local"
- name: Create snmp user - name: Remove snmp user
nxos_snmp_user: &create
user: ntc
group: network-operator
authentication: md5
pwd: N$tOpe%1
privacy: HelloU$er1
encrypt: true
provider: "{{ connection }}"
register: result
- assert: &true
that:
- "result.changed == true"
- name: delete snmp user
nxos_snmp_user: &remove nxos_snmp_user: &remove
user: ntc user: ntc
group: network-operator
authentication: md5
pwd: Testing1%
privacy: HelloU$er1
encrypt: true
state: absent state: absent
provider: "{{ connection }}" provider: "{{ connection }}"
register: result
- assert: *true - pause:
seconds: 5
- block:
- name: Create snmp user
nxos_snmp_user: &create
user: ntc
group: network-operator
authentication: md5
pwd: N$tOpe%1
privacy: HelloU$er1
encrypt: true
provider: "{{ connection }}"
register: result
- assert: &true
that:
- "result.changed == true"
- name: Add another group to user
nxos_snmp_user: &chg
user: ntc
group: network-admin
provider: "{{ connection }}"
register: result
- assert: *true
- name: "Check Idempotence"
nxos_snmp_user: *chg
register: result
- assert: &false
that:
- "result.changed == false"
- name: Remove group from user
nxos_snmp_user: &remg
user: ntc
group: network-admin
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- pause:
seconds: 5
- name: "Check Idempotence"
nxos_snmp_user: *remg
register: result
- assert: *false
- name: delete snmp user
nxos_snmp_user: &remove1
user: ntc
group: network-operator
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- pause:
seconds: 5
- name: "Remove Idempotence"
nxos_snmp_user: *remove1
register: result
- name: "Remove Idempotence" - assert: *false
nxos_snmp_user: *remove
register: result
- assert: &false always:
that: - name: delete snmp user
- "result.changed == false" nxos_snmp_user: *remove
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_user sanity test" - debug: msg="END connection={{ ansible_connection }} nxos_snmp_user sanity test"

@ -1748,8 +1748,6 @@ lib/ansible/modules/network/nxos/nxos_reboot.py E325
lib/ansible/modules/network/nxos/nxos_smu.py E324 lib/ansible/modules/network/nxos/nxos_smu.py E324
lib/ansible/modules/network/nxos/nxos_snapshot.py E325 lib/ansible/modules/network/nxos/nxos_snapshot.py E325
lib/ansible/modules/network/nxos/nxos_snapshot.py E326 lib/ansible/modules/network/nxos/nxos_snapshot.py E326
lib/ansible/modules/network/nxos/nxos_snmp_user.py E325
lib/ansible/modules/network/nxos/nxos_snmp_user.py E326
lib/ansible/modules/network/nxos/nxos_system.py E325 lib/ansible/modules/network/nxos/nxos_system.py E325
lib/ansible/modules/network/nxos/nxos_udld.py E325 lib/ansible/modules/network/nxos/nxos_udld.py E325
lib/ansible/modules/network/nxos/nxos_udld.py E326 lib/ansible/modules/network/nxos/nxos_udld.py E326

Loading…
Cancel
Save