nxos bugfixes stable-2.5 (#39719)

* Handle nxos_feature issue where json isn't supported (#39150)

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

* Integration Tests only: nxos_snmp_contact (#39318)

* add integration test cases for snmp_contact

* removing unnecessary files

(cherry picked from commit bdb75cd82c)

* fix nxos_ntp issues (#39178)

* fix nxos_ntp issues

* review comments

* fix idempotent fail case

(cherry picked from commit 2f99a17856)

* nxos_interface: AttributeError: 'NoneType' object has no attribute 'group' (#38544)

This fixes an issue we recently encounteredi with nxos_interface:

```
Traceback (most recent call last):
  File "/tmp/ansible_JmLoba/ansible_module_nxos_interface.py", line 777, in main
    have = map_config_to_obj(want, module)
  File "/tmp/ansible_JmLoba/ansible_module_nxos_interface.py", line 606, in map_config_to_obj
    obj['speed'] = re.search(r'speed (\d+)', body).group(1)
AttributeError: 'NoneType' object has no attribute 'group'
```

(cherry picked from commit dca6e2d94d)

* fix nxos_snmp_community issues (#39258)

(cherry picked from commit 1afec5a48e)

* Add aggregate example in nxos_l2_interface module doc (#39275)

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

* Fix misuse of 'self' in lib/ansible/module_utils/network/eos/eos.py. … (#39074)

* Fix misuse of 'self' in lib/ansible/module_utils/network/eos/eos.py. Method load_config

* Fix all instances of self.config(self,...

(cherry picked from commit 80d7e22f5e)

* Fix for nxos_snmp_host issues (#39642)

* fix snmp_host issues

* source files

* fix shippable

* remove defaults to match arg spec

(cherry picked from commit f99bae1776)

* fix nxos_snmp_traps issues (#39444)

* fix snmp_traps code

* add IT cases

* fix shippable

* fix shippable without ignore

(cherry picked from commit 99748cbfa4)

* changelog

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

@ -0,0 +1,2 @@
bugfixes:
- Fix misuse of self in module_utils/network/eos/eos.py (https://github.com/ansible/ansible/pull/39074)

@ -20,3 +20,10 @@ bugfixes:
- nxos_igmp_snooping - Fix nxos_igmp_snooping (https://github.com/ansible/ansible/pull/38566)
- nxos_ntp_auth - Fix nxos_ntp_auth issues (https://github.com/ansible/ansible/pull/38824)
- nxos_ntp_options - Fix nxos_ntp_options issues (https://github.com/ansible/ansible/pull/38695)
- nxos_feature - Handle nxos_feature issue where json isn't supported (https://github.com/ansible/ansible/pull/39150)
- nxos_ntp - Fix nxos_ntp issues (https://github.com/ansible/ansible/pull/39178)
- nxos_interface - Fix AttributeError NoneType object has no attribute group (https://github.com/ansible/ansible/pull/38544)
- nxos_snmp_community - Fix nxos_snmp_community issues (https://github.com/ansible/ansible/pull/39258)
- 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_traps - Fix nxos_snmp_traps issues (https://github.com/ansible/ansible/pull/39444)

@ -232,7 +232,7 @@ class Cli:
if not all((bool(use_session), self.supports_sessions)):
if commit:
return self.configure(self, commands)
return self.configure(commands)
else:
self._module.warn("EOS can not check config without config session")
result = {'changed': True}
@ -420,7 +420,7 @@ class Eapi:
if not all((bool(use_session), self.supports_sessions)):
if commit:
return self.configure(self, config)
return self.configure(config)
else:
self._module.warn("EOS can not check config without config session")
result = {'changed': True}

@ -72,6 +72,7 @@ commands:
import re
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.nxos.nxos import load_config, run_commands
from ansible.module_utils.network.nxos.nxos import get_capabilities, nxos_argument_spec
@ -130,8 +131,13 @@ def validate_feature(module, mode='show'):
how they are configured'''
feature = module.params['feature']
info = get_capabilities(module).get('device_info', {})
os_version = info.get('network_os_version', '')
try:
info = get_capabilities(module)
device_info = info.get('device_info', {})
os_version = device_info.get('network_os_version', '')
except ConnectionError:
os_version = ''
if '8.1' in os_version:
feature_to_be_mapped = {

@ -616,15 +616,17 @@ def map_config_to_obj(want, module):
command = 'show run interface {0}'.format(obj['name'])
body = execute_show_command(command, module)[0]
if 'speed' in body:
obj['speed'] = re.search(r'speed (\d+)', body).group(1)
else:
speed_match = re.search(r'speed (\d+)', body)
if speed_match is None:
obj['speed'] = 'auto'
if 'duplex' in body:
obj['duplex'] = re.search(r'duplex (\S+)', body).group(1)
else:
obj['speed'] = speed_match.group(1)
duplex_match = re.search(r'duplex (\S+)', body)
if duplex_match is None:
obj['duplex'] = 'auto'
else:
obj['duplex'] = duplex_match.group(1)
if 'ip forward' in body:
obj['ip_forward'] = 'enable'

@ -97,6 +97,13 @@ EXAMPLES = """
mode: trunk
trunk_vlans: 51-4094
state: absent
- name: Aggregate Configure interfaces for access_vlan with aggregate
nxos_l2_interface:
aggregate:
- { name: "Ethernet1/2", access_vlan: 6 }
- { name: "Ethernet1/7", access_vlan: 15 }
mode: access
"""
RETURN = """

@ -25,47 +25,34 @@ options:
server:
description:
- Network address of NTP server.
required: false
default: null
peer:
description:
- Network address of NTP peer.
required: false
default: null
key_id:
description:
- Authentication key identifier to use with
given NTP server or peer.
required: false
default: null
given NTP server or peer or keyword 'default'.
prefer:
description:
- Makes given NTP server or peer the preferred
NTP server or peer for the device.
required: false
default: null
choices: ['enabled', 'disabled']
vrf_name:
description:
- Makes the device communicate with the given
NTP server or peer over a specific VRF.
required: false
default: null
NTP server or peer over a specific VRF or
keyword 'default'.
source_addr:
description:
- Local source address from which NTP messages are sent.
required: false
default: null
- Local source address from which NTP messages are sent
or keyword 'default'
source_int:
description:
- Local source interface from which NTP messages are sent.
Must be fully qualified interface name.
required: false
default: null
Must be fully qualified interface name or keyword 'default'
state:
description:
- Manage the state of the resource.
required: false
default: present
choices: ['present','absent']
'''
@ -186,10 +173,12 @@ def get_ntp_peer(module):
split_ntp = ntp.splitlines()
for peer_line in split_ntp:
if 'access-group' in peer_line:
continue
ntp_peer = {}
try:
peer_address = None
vrf_name = None
vrf_name = 'default'
prefer = None
key_id = None
match_ntp = re.match(ntp_regex, peer_line, re.DOTALL)
@ -261,11 +250,18 @@ def set_ntp_server_peer(peer_type, address, prefer, key_id, vrf_name):
def config_ntp(delta, existing):
address = delta.get('address', existing.get('address'))
peer_type = delta.get('peer_type', existing.get('peer_type'))
vrf_name = delta.get('vrf_name', existing.get('vrf_name'))
key_id = delta.get('key_id', existing.get('key_id'))
prefer = delta.get('prefer', existing.get('prefer'))
if (delta.get('address') or delta.get('peer_type') or delta.get('vrf_name') or
delta.get('key_id') or delta.get('prefer')):
address = delta.get('address', existing.get('address'))
peer_type = delta.get('peer_type', existing.get('peer_type'))
key_id = delta.get('key_id', existing.get('key_id'))
prefer = delta.get('prefer', existing.get('prefer'))
vrf_name = delta.get('vrf_name', existing.get('vrf_name'))
if delta.get('key_id') == 'default':
key_id = None
else:
peer_type = None
prefer = None
source_type = delta.get('source_type')
source = delta.get('source')
@ -281,6 +277,9 @@ def config_ntp(delta, existing):
ntp_cmds = []
if peer_type:
if existing.get('peer_type') and existing.get('address'):
ntp_cmds.append('no ntp {0} {1}'.format(existing.get('peer_type'),
existing.get('address')))
ntp_cmds.append(set_ntp_server_peer(
peer_type, address, prefer, key_id, vrf_name))
if source:
@ -288,7 +287,11 @@ def config_ntp(delta, existing):
existing_source = existing.get('source')
if existing_source_type and source_type != existing_source_type:
ntp_cmds.append('no ntp {0} {1}'.format(existing_source_type, existing_source))
ntp_cmds.append('ntp {0} {1}'.format(source_type, source))
if source == 'default':
if existing_source_type and existing_source:
ntp_cmds.append('no ntp {0} {1}'.format(existing_source_type, existing_source))
else:
ntp_cmds.append('ntp {0} {1}'.format(source_type, source))
return ntp_cmds
@ -324,6 +327,7 @@ def main():
source_addr = module.params['source_addr']
source_int = module.params['source_int']
state = module.params['state']
if source_int is not None:
source_int = source_int.lower()
@ -365,6 +369,9 @@ def main():
if state == 'present':
delta = dict(set(proposed.items()).difference(existing.items()))
if delta.get('key_id') and delta.get('key_id') == 'default':
if not existing.get('key_id'):
delta.pop('key_id')
if delta:
command = config_ntp(delta, existing)
if command:

@ -42,23 +42,16 @@ options:
access:
description:
- Access type for community.
required: false
default: null
choices: ['ro','rw']
group:
description:
- Group to which the community belongs.
required: false
default: null
acl:
description:
- ACL name to filter snmp requests.
required: false
default: 1
- ACL name to filter snmp requests or keyword 'default'.
state:
description:
- Manage the state of the resource.
required: true
default: present
choices: ['present','absent']
'''
@ -156,7 +149,8 @@ def get_snmp_community(module, name):
def config_snmp_community(delta, community):
CMDS = {
'group': 'snmp-server community {0} group {group}',
'acl': 'snmp-server community {0} use-acl {acl}'
'acl': 'snmp-server community {0} use-acl {acl}',
'no_acl': 'no snmp-server community {0} use-acl {no_acl}'
}
commands = []
for k, v in delta.items():
@ -209,6 +203,10 @@ def main():
args = dict(group=group, acl=acl)
proposed = dict((k, v) for k, v in args.items() if v is not None)
delta = dict(set(proposed.items()).difference(existing.items()))
if delta.get('acl') == 'default':
delta.pop('acl')
if existing.get('acl'):
delta['no_acl'] = existing.get('acl')
commands = []

@ -42,10 +42,8 @@ options:
required: true
version:
description:
- SNMP version.
required: false
default: v2c
choices: ['v2c', 'v3']
- SNMP version. If this is not specified, v1 is used.
choices: ['v1', 'v2c', 'v3']
v3:
description:
- Use this when verion is v3. SNMPv3 Security level.
@ -53,38 +51,36 @@ options:
community:
description:
- Community string or v3 username.
required: false
default: null
udp:
description:
- UDP port number (0-65535).
required: false
default: null
default: 162
snmp_type:
description:
- type of message to send to host.
required: false
default: trap
- type of message to send to host. If this is not
specified, trap type is used.
choices: ['trap', 'inform']
vrf:
description:
- VRF to use to source traffic to source.
required: false
default: null
If state = absent, the vrf is removed.
vrf_filter:
description:
- Name of VRF to filter.
required: false
default: null
If state = absent, the vrf is removed from the filter.
src_intf:
description:
- Source interface.
required: false
default: null
- Source interface. Must be fully qualified interface name.
If state = absent, the interface is removed.
state:
description:
- Manage the state of the resource.
required: true
- Manage the state of the resource. If state = present, the
host is added to the configuration. If only vrf and/or
vrf_filter and/or src_intf are given, they will be added to
the existing host configuration. If state = absent, the
host is removed if community parameter is given. It is possible
to remove only vrf and/or src_int and/or vrf_filter
by providing only those parameters and no community parameter.
default: present
choices: ['present','absent']
'''
@ -144,7 +140,7 @@ def flatten_list(command_lists):
return flat_command_list
def get_snmp_host(host, module):
def get_snmp_host(host, udp, module):
body = execute_show_command('show snmp host', module)
host_map = {
@ -173,7 +169,7 @@ def get_snmp_host(host, module):
resource_table = [resource_table]
for each in resource_table:
key = str(each['host'])
key = str(each['host']) + '_' + str(each['port']).strip()
src = each.get('src_intf')
host_resource = apply_key_map(host_map, each)
@ -201,7 +197,7 @@ def get_snmp_host(host, module):
resource_table = [resource_table]
for each in resource_table:
key = str(each['address'])
key = str(each['address']) + '_' + str(each['port']).strip()
src = each.get('src_intf')
host_resource = apply_key_map(host_map_5k, each)
@ -210,22 +206,23 @@ def get_snmp_host(host, module):
if re.search(r'interface:', src):
host_resource['src_intf'] = src.split(':')[1].strip()
vrf = each.get('use_vrf_name')
if vrf:
host_resource['vrf'] = vrf.strip()
vrf_filt = each.get('TABLE_filter_vrf')
if vrf_filt:
vrf_filter = vrf_filt['ROW_filter_vrf']['filter_vrf_name'].split(',')
filters = [vrf.strip() for vrf in vrf_filter]
host_resource['vrf_filter'] = filters
vrf = each.get('use_vrf_name')
if vrf:
host_resource['vrf'] = vrf.strip()
resource[key] = host_resource
except (KeyError, AttributeError, TypeError):
return resource
except (AttributeError, TypeError):
return resource
find = resource.get(host)
find = resource.get(host + '_' + udp)
if find:
fix_find = {}
@ -239,24 +236,54 @@ def get_snmp_host(host, module):
return {}
def remove_snmp_host(host, existing):
def remove_snmp_host(host, udp, existing):
commands = []
if existing['version'] == 'v3':
existing['version'] = '3'
command = 'no snmp-server host {0} {snmp_type} version \
{version} {v3} {community}'.format(host, **existing)
{version} {v3} {community} udp-port {1}'.format(host, udp, **existing)
elif existing['version'] == 'v2c':
existing['version'] = '2c'
command = 'no snmp-server host {0} {snmp_type} version \
{version} {community}'.format(host, **existing)
{version} {community} udp-port {1}'.format(host, udp, **existing)
elif existing['version'] == 'v1':
existing['version'] = '1'
command = 'no snmp-server host {0} {snmp_type} version \
{version} {community} udp-port {1}'.format(host, udp, **existing)
if command:
commands.append(command)
return commands
def config_snmp_host(delta, proposed, existing, module):
def remove_vrf(host, udp, proposed, existing):
commands = []
if existing.get('vrf'):
commands.append('no snmp-server host {0} use-vrf \
{1} udp-port {2}'.format(host, proposed.get('vrf'), udp))
return commands
def remove_filter(host, udp, proposed, existing):
commands = []
if existing.get('vrf_filter'):
if proposed.get('vrf_filter') in existing.get('vrf_filter'):
commands.append('no snmp-server host {0} filter-vrf \
{1} udp-port {2}'.format(host, proposed.get('vrf_filter'), udp))
return commands
def remove_src(host, udp, proposed, existing):
commands = []
if existing.get('src_intf'):
commands.append('no snmp-server host {0} source-interface \
{1} udp-port {2}'.format(host, proposed.get('src_intf'), udp))
return commands
def config_snmp_host(delta, udp, proposed, existing, module):
commands = []
command_builder = []
host = proposed['snmp_host']
@ -275,7 +302,9 @@ def config_snmp_host(delta, proposed, existing, module):
version = version or existing.get('version')
if version:
if version == 'v2c':
if version == 'v1':
vn = '1'
elif version == 'v2c':
vn = '2c'
elif version == 'v3':
vn = '3'
@ -291,21 +320,23 @@ def config_snmp_host(delta, proposed, existing, module):
community_string = community or existing.get('community')
command_builder.append(community_string)
udp_string = ' udp-port {0}'.format(udp)
command_builder.append(udp_string)
cmd = ' '.join(command_builder)
commands.append(cmd)
CMDS = {
'vrf_filter': 'snmp-server host {0} filter-vrf {vrf_filter}',
'vrf': 'snmp-server host {0} use-vrf {vrf}',
'udp': 'snmp-server host {0} udp-port {udp}',
'src_intf': 'snmp-server host {0} source-interface {src_intf}'
'vrf_filter': 'snmp-server host {0} filter-vrf {vrf_filter} udp-port {1}',
'vrf': 'snmp-server host {0} use-vrf {vrf} udp-port {1}',
'src_intf': 'snmp-server host {0} source-interface {src_intf} udp-port {1}'
}
for key in delta:
command = CMDS.get(key)
if command:
cmd = command.format(host, **delta)
cmd = command.format(host, udp, **delta)
commands.append(cmd)
return commands
@ -314,13 +345,13 @@ def main():
argument_spec = dict(
snmp_host=dict(required=True, type='str'),
community=dict(type='str'),
udp=dict(type='str'),
version=dict(choices=['v2c', 'v3'], default='v2c'),
udp=dict(type='str', default='162'),
version=dict(choices=['v1', 'v2c', 'v3']),
src_intf=dict(type='str'),
v3=dict(choices=['noauth', 'auth', 'priv']),
vrf_filter=dict(type='str'),
vrf=dict(type='str'),
snmp_type=dict(choices=['trap', 'inform'], default='trap'),
snmp_type=dict(choices=['trap', 'inform']),
state=dict(choices=['absent', 'present'], default='present'),
)
@ -343,17 +374,35 @@ def main():
snmp_type = module.params['snmp_type']
state = module.params['state']
if snmp_type == 'inform' and version != 'v3':
module.fail_json(msg='inform requires snmp v3')
existing = get_snmp_host(snmp_host, udp, module)
if version is None:
if existing:
version = existing.get('version')
else:
version = 'v1'
if snmp_type is None:
if existing:
snmp_type = existing.get('snmp_type')
else:
snmp_type = 'trap'
if version == 'v2c' and v3:
if v3 is None:
if version == 'v3' and existing:
v3 = existing.get('v3')
if snmp_type == 'inform' and version == 'v1':
module.fail_json(msg='inform requires snmp v2c or v3')
if (version == 'v1' or version == 'v2c') and v3:
module.fail_json(msg='param: "v3" should not be used when '
'using version v2c')
'using version v1 or v2c')
if not any([vrf_filter, vrf, udp, src_intf]):
if not all([snmp_type, version, community]):
if not any([vrf_filter, vrf, src_intf]):
if not all([snmp_type, version, community, udp]):
module.fail_json(msg='when not configuring options like '
'vrf_filter, vrf, udp, and src_intf,'
'vrf_filter, vrf, and src_intf,'
'the following params are required: '
'type, version, community')
@ -361,8 +410,6 @@ def main():
module.fail_json(msg='when using version=v3, the param v3 '
'(options: auth, noauth, priv) is also required')
existing = get_snmp_host(snmp_host, module)
# existing returns the list of vrfs configured for a given host
# checking to see if the proposed is in the list
store = existing.get('vrf_filter')
@ -373,27 +420,34 @@ def main():
existing['vrf_filter'] = vrf_filter
commands = []
args = dict(
community=community,
snmp_host=snmp_host,
udp=udp,
version=version,
src_intf=src_intf,
vrf_filter=vrf_filter,
v3=v3,
vrf=vrf,
snmp_type=snmp_type
)
proposed = dict((k, v) for k, v in args.items() if v is not None)
if state == 'absent' and existing:
command = remove_snmp_host(snmp_host, existing)
commands.append(command)
if proposed.get('community'):
commands.append(remove_snmp_host(snmp_host, udp, existing))
else:
if proposed.get('src_intf'):
commands.append(remove_src(snmp_host, udp, proposed, existing))
if proposed.get('vrf'):
commands.append(remove_vrf(snmp_host, udp, proposed, existing))
if proposed.get('vrf_filter'):
commands.append(remove_filter(snmp_host, udp, proposed, existing))
elif state == 'present':
args = dict(
community=community,
snmp_host=snmp_host,
udp=udp,
version=version,
src_intf=src_intf,
vrf_filter=vrf_filter,
v3=v3,
vrf=vrf,
snmp_type=snmp_type
)
proposed = dict((k, v) for k, v in args.items() if v is not None)
delta = dict(set(proposed.items()).difference(existing.items()))
if delta:
command = config_snmp_host(delta, proposed, existing, module)
command = config_snmp_host(delta, udp, proposed, existing, module)
commands.append(command)
cmds = flatten_list(commands)

@ -42,9 +42,10 @@ options:
description:
- Case sensitive group.
required: true
choices: ['aaa', 'bridge', 'callhome', 'cfs', 'config', 'entity',
'feature-control', 'hsrp', 'license', 'link', 'lldp', 'ospf', 'pim',
'rf', 'rmon', 'snmp', 'storm-control', 'stpx', 'sysmgr', 'system',
choices: ['aaa', 'bfd', 'bgp', 'bridge', 'callhome', 'cfs', 'config',
'eigrp', 'entity', 'feature-control', 'generic', 'hsrp', 'license',
'link', 'lldp', 'mmode', 'ospf', 'pim', 'rf', 'rmon', 'snmp',
'storm-control', 'stpx', 'switchfabric', 'syslog', 'sysmgr', 'system',
'upgrade', 'vtp', 'all']
state:
description:
@ -83,25 +84,12 @@ from ansible.module_utils.basic import AnsibleModule
def execute_show_command(command, module):
command = {
'command': command,
'output': 'json',
'output': 'text',
}
return run_commands(module, command)
def apply_key_map(key_map, table):
new_dict = {}
for key, value in table.items():
new_key = key_map.get(key)
if new_key:
value = table.get(key)
if value:
new_dict[new_key] = str(value)
else:
new_dict[new_key] = value
return new_dict
def flatten_list(command_lists):
flat_command_list = []
for command in command_lists:
@ -113,61 +101,44 @@ def flatten_list(command_lists):
def get_snmp_traps(group, module):
body = execute_show_command('show snmp trap', module)
trap_key = {
'description': 'trap',
'isEnabled': 'enabled'
}
trap_key_5k = {
'trap': 'trap',
'enabled': 'enabled'
}
body = execute_show_command('show run snmp all', module)[0].split('\n')
resource = {}
feature_list = ['aaa', 'bridge', 'callhome', 'cfs', 'config',
'entity', 'feature-control', 'hsrp', 'license',
'link', 'lldp', 'ospf', 'pim', 'rf', 'rmon',
'snmp', 'storm-control', 'stpx', 'sysmgr',
'system', 'upgrade', 'vtp']
try:
resource_table = body[0]['TABLE_snmp_trap']['ROW_snmp_trap']
for each_feature in feature_list:
resource[each_feature] = []
for each_resource in resource_table:
key = str(each_resource['trap_type'])
mapped_trap = apply_key_map(trap_key, each_resource)
if key != 'Generic':
resource[key].append(mapped_trap)
except KeyError:
try:
resource_table = body[0]['TABLE_mib']['ROW_mib']
for each_feature in feature_list:
resource[each_feature] = []
for each_resource in resource_table:
key = str(each_resource['mib'])
each_resource = each_resource['TABLE_trap']['ROW_trap']
mapped_trap = apply_key_map(trap_key_5k, each_resource)
if key != 'Generic':
resource[key].append(mapped_trap)
except (KeyError, AttributeError):
return resource
except AttributeError:
return resource
feature_list = ['aaa', 'bfd', 'bgp', 'bridge', 'callhome', 'cfs', 'config',
'eigrp', 'entity', 'feature-control', 'generic', 'hsrp',
'license', 'link', 'lldp', 'mmode', 'ospf', 'pim',
'rf', 'rmon', 'snmp', 'storm-control', 'stpx',
'switchfabric', 'syslog', 'sysmgr', 'system', 'upgrade',
'vtp']
for each in feature_list:
for line in body:
if each == 'ospf':
# ospf behaves differently when routers are present
if 'snmp-server enable traps ospf' == line:
resource[each] = True
break
else:
if 'enable traps {0}'.format(each) in line:
if 'no ' in line:
resource[each] = False
break
else:
resource[each] = True
for each in feature_list:
if resource.get(each) is None:
# on some platforms, the 'no' cmd does not
# show up and so check if the feature is enabled
body = execute_show_command('show run | inc feature', module)[0]
if 'feature {0}'.format(each) in body:
resource[each] = False
find = resource.get(group, None)
if group == 'all'.lower():
return resource
elif find:
trap_resource = {group: resource[group]}
elif find is not None:
trap_resource = {group: find}
return trap_resource
else:
# if 'find' is None, it means that 'group' is a
@ -183,26 +154,22 @@ def get_trap_commands(group, state, existing, module):
if group == 'all':
if state == 'disabled':
for feature in existing:
trap_commands = ['no snmp-server enable traps {0}'.format(feature) for
trap in existing[feature] if trap['enabled'] == 'Yes']
trap_commands = list(set(trap_commands))
commands.append(trap_commands)
if existing[feature]:
trap_command = 'no snmp-server enable traps {0}'.format(feature)
commands.append(trap_command)
elif state == 'enabled':
for feature in existing:
trap_commands = ['snmp-server enable traps {0}'.format(feature) for
trap in existing[feature] if trap['enabled'] == 'No']
trap_commands = list(set(trap_commands))
commands.append(trap_commands)
if existing[feature] is False:
trap_command = 'snmp-server enable traps {0}'.format(feature)
commands.append(trap_command)
else:
if group in existing:
for each_trap in existing[group]:
check = each_trap['enabled']
if check.lower() == 'yes':
enabled = True
if check.lower() == 'no':
disabled = True
if existing[group]:
enabled = True
else:
disabled = True
if state == 'disabled' and enabled:
commands.append(['no snmp-server enable traps {0}'.format(group)])
@ -218,11 +185,12 @@ def get_trap_commands(group, state, existing, module):
def main():
argument_spec = dict(
state=dict(choices=['enabled', 'disabled'], default='enabled'),
group=dict(choices=['aaa', 'bridge', 'callhome', 'cfs', 'config',
'entity', 'feature-control', 'hsrp',
'license', 'link', 'lldp', 'ospf', 'pim', 'rf',
'rmon', 'snmp', 'storm-control', 'stpx',
'sysmgr', 'system', 'upgrade', 'vtp', 'all'],
group=dict(choices=['aaa', 'bfd', 'bgp', 'bridge', 'callhome', 'cfs', 'config',
'eigrp', 'entity', 'feature-control', 'generic', 'hsrp',
'license', 'link', 'lldp', 'mmode', 'ospf', 'pim',
'rf', 'rmon', 'snmp', 'storm-control', 'stpx',
'switchfabric', 'syslog', 'sysmgr', 'system', 'upgrade',
'vtp', 'all'],
required=True),
)

@ -39,6 +39,25 @@
that:
- "result.changed == false"
- name: Configure ntp with some defaults
nxos_ntp: &config1
peer: 1.2.3.4
key_id: default
prefer: enabled
vrf_name: default
source_addr: default
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_ntp: *config1
register: result
- assert: *false
- name: Remove ntp config
nxos_ntp: *remove
register: result
@ -51,6 +70,50 @@
- assert: *false
- name: Configure ntp again
nxos_ntp: &config2
source_int: Ethernet1/3
peer: 1.2.3.4
prefer: enabled
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_ntp: *config2
register: result
- assert: *false
- name: Remove source interface
nxos_ntp: &config3
source_int: default
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_ntp: *config3
register: result
- assert: *false
- name: Remove ntp
nxos_ntp: *remove
register: result
- assert: *true
- name: Remove Idempotence Check
nxos_ntp: *remove
register: result
- assert: *false
always:
- name: Remove ntp config
nxos_ntp: *remove

@ -17,7 +17,6 @@
nxos_snmp_community: &config
community: TESTING7
group: network-operator
#access: ro
state: present
provider: "{{ connection }}"
register: result
@ -34,6 +33,22 @@
that:
- "result.changed == false"
- name: Change snmp_community group
nxos_snmp_community: &chg
community: TESTING7
group: network-admin
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_community: *chg
register: result
- assert: *false
- name: Remove snmp_community
nxos_snmp_community: *remove
register: result
@ -91,6 +106,40 @@
- assert: *false
- name: Change acl
nxos_snmp_community: &chgacl
community: TESTING7
access: rw
acl: new_acl
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_community: *chgacl
register: result
- assert: *false
- name: Remove acl
nxos_snmp_community: &removeacl
community: TESTING7
access: rw
acl: default
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_community: *removeacl
register: result
- assert: *false
always:
- name: Cleanup
nxos_snmp_community: *remove

@ -0,0 +1,2 @@
dependencies:
- prepare_nxos_tests

@ -0,0 +1,33 @@
---
- name: collect common cli test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
connection: local
register: cli_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ cli_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli connection={}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local connection={{ cli }}"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,3 @@
---
- { include: cli.yaml, tags: ['cli'] }
- { include: nxapi.yaml, tags: ['nxapi'] }

@ -0,0 +1,27 @@
---
- name: collect common nxapi test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect nxapi test cases
find:
paths: "{{ role_path }}/tests/nxapi"
patterns: "{{ testcase }}.yaml"
connection: local
register: nxapi_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ nxapi_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local connection={{ nxapi }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,64 @@
---
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_community sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
- name: Setup - Remove snmp_contact if configured
nxos_snmp_contact: &remove
contact: Test
state: absent
provider: "{{ connection }}"
- block:
- name: Configure snmp contact
nxos_snmp_contact: &config
contact: Testing
state: present
provider: "{{ connection }}"
register: result
- assert: &true
that:
- "result.changed == true"
- name: Idempotence Check
nxos_snmp_contact: *config
register: result
- assert: &false
that:
- "result.changed == false"
- name: Change snmp contact
nxos_snmp_contact: &config1
contact: Test
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_contact: *config1
register: result
- assert: *false
- name: Remove snmp contact
nxos_snmp_contact: *remove
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_contact: *remove
register: result
- assert: *false
always:
- name: Cleanup
nxos_snmp_contact: *remove
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_community sanity test"

@ -0,0 +1,129 @@
---
- set_fact: snmp_type="trap"
- set_fact: snmp_version="v1"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
# Select interface for test
- set_fact: intname="{{ nxos_int1 }}"
when: not (platform is match("N5K"))
- name: Setup - Remove snmp_host if configured
nxos_snmp_host: &remove
snmp_host: 3.3.3.3
community: TESTING
version: "{{ snmp_version }}"
snmp_type: "{{ snmp_type }}"
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
udp: 222
state: absent
provider: "{{ connection }}"
ignore_errors: yes
- block:
- name: Configure snmp host
nxos_snmp_host: &config
snmp_host: 3.3.3.3
community: TESTING
version: "{{ snmp_version }}"
snmp_type: "{{ snmp_type }}"
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
udp: 222
state: present
provider: "{{ connection }}"
register: result
- assert: &true
that:
- "result.changed == true"
- name: Idempotence Check
nxos_snmp_host: *config
register: result
- assert: &false
that:
- "result.changed == false"
- block:
- name: Add another vrf to filter
nxos_snmp_host: &config1
snmp_host: 3.3.3.3
vrf_filter: default
udp: 222
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *config1
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: remove some configuration
nxos_snmp_host: &rem1
snmp_host: 3.3.3.3
udp: 222
src_intf: "{{ intname|default(omit) }}"
vrf: management
vrf_filter: management
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem1
register: result
- assert: *false
- block:
- name: remove some more configuration
nxos_snmp_host: &rem2
snmp_host: 3.3.3.3
udp: 222
vrf_filter: default
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem2
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: Cleanup
nxos_snmp_host: *remove
register: result
- assert: *true
- name: Cleanup Idempotence
nxos_snmp_host: *remove
register: result
- assert: *false
always:
- name: Cleanup
nxos_snmp_host: *remove
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"

@ -1,8 +1,8 @@
---
- set_fact: snmp_type="trap"
- set_fact: snmp_type="inform"
- set_fact: snmp_version="v2c"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
@ -19,6 +19,7 @@
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
udp: 222
state: absent
provider: "{{ connection }}"
ignore_errors: yes
@ -34,6 +35,7 @@
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
udp: 222
state: present
provider: "{{ connection }}"
register: result
@ -50,7 +52,63 @@
that:
- "result.changed == false"
always:
- block:
- name: Add another vrf to filter
nxos_snmp_host: &config1
snmp_host: 3.3.3.3
vrf_filter: default
udp: 222
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *config1
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: remove some configuration
nxos_snmp_host: &rem1
snmp_host: 3.3.3.3
udp: 222
src_intf: "{{ intname|default(omit) }}"
vrf: management
vrf_filter: management
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem1
register: result
- assert: *false
- block:
- name: remove some more configuration
nxos_snmp_host: &rem2
snmp_host: 3.3.3.3
udp: 222
vrf_filter: default
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem2
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: Cleanup
nxos_snmp_host: *remove
register: result
@ -63,4 +121,8 @@
- assert: *false
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
always:
- name: Cleanup
nxos_snmp_host: *remove
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"

@ -3,7 +3,7 @@
- set_fact: snmp_version="v3"
- set_fact: snmp_auth="noauth"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
@ -11,13 +11,17 @@
- set_fact: intname="{{ nxos_int1 }}"
when: not (platform is match("N5K"))
- set_fact: run="true"
- set_fact: run="false"
when: platform is match('N35')
- name: Setup - Remove snmp_host if configured
nxos_snmp_host: &remove
snmp_host: 3.3.3.3
community: TESTING
v3: "{{ snmp_auth|default(omit) }}"
version: "{{ snmp_version }}"
snmp_type: "{{ snmp_type }}"
v3: "{{ snmp_auth }}"
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
@ -53,9 +57,60 @@
that:
- "result.changed == false"
when: not (platform is match('N35'))
- block:
- name: Add another vrf to filter
nxos_snmp_host: &config1
snmp_host: 3.3.3.3
vrf_filter: default
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *config1
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: remove some configuration
nxos_snmp_host: &rem1
snmp_host: 3.3.3.3
src_intf: "{{ intname|default(omit) }}"
vrf: management
vrf_filter: management
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem1
register: result
- assert: *false
- block:
- name: remove some more configuration
nxos_snmp_host: &rem2
snmp_host: 3.3.3.3
vrf_filter: default
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem2
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
always:
- name: Cleanup
nxos_snmp_host: *remove
register: result
@ -68,4 +123,11 @@
- assert: *false
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
when: run
always:
- name: Cleanup
nxos_snmp_host: *remove
register: result
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"

@ -1,21 +1,27 @@
---
- set_fact: snmp_type="trap"
- set_fact: snmp_version="v3"
- set_fact: snmp_auth="noauth"
- set_fact: snmp_auth="priv"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
# Select interface for test
- set_fact: intname="{{ nxos_int1 }}"
when: not (platform is match("N5K"))
- name: Setup - Remove snmp_host if configured
nxos_snmp_host: &remove
snmp_host: 3.3.3.3
community: TESTING
udp: 222
v3: "{{ snmp_auth|default(omit) }}"
version: "{{ snmp_version }}"
snmp_type: "{{ snmp_type }}"
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
state: absent
provider: "{{ connection }}"
ignore_errors: yes
@ -26,11 +32,13 @@
nxos_snmp_host: &config
snmp_host: 3.3.3.3
community: TESTING
udp: 222
v3: "{{ snmp_auth|default(omit) }}"
version: "{{ snmp_version }}"
snmp_type: "{{ snmp_type }}"
vrf: management
vrf_filter: management
src_intf: "{{ intname|default(omit) }}"
state: present
provider: "{{ connection }}"
register: result
@ -47,7 +55,63 @@
that:
- "result.changed == false"
always:
- block:
- name: Add another vrf to filter
nxos_snmp_host: &config1
snmp_host: 3.3.3.3
udp: 222
vrf_filter: default
state: present
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *config1
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: remove some configuration
nxos_snmp_host: &rem1
snmp_host: 3.3.3.3
udp: 222
src_intf: "{{ intname|default(omit) }}"
vrf: management
vrf_filter: management
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem1
register: result
- assert: *false
- block:
- name: remove some more configuration
nxos_snmp_host: &rem2
snmp_host: 3.3.3.3
udp: 222
vrf_filter: default
state: absent
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_host: *rem2
register: result
- assert: *false
when: not (platform is match('N35|N5K'))
- name: Cleanup
nxos_snmp_host: *remove
register: result
@ -60,4 +124,9 @@
- assert: *false
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }}sanity test"
always:
- name: Cleanup
nxos_snmp_host: *remove
register: result
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_host {{ snmp_type }} {{ snmp_version }} sanity test"

@ -0,0 +1,2 @@
dependencies:
- prepare_nxos_tests

@ -0,0 +1,33 @@
---
- name: collect common cli test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect cli test cases
find:
paths: "{{ role_path }}/tests/cli"
patterns: "{{ testcase }}.yaml"
connection: local
register: cli_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ cli_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=network_cli)
include: "{{ test_case_to_run }} ansible_connection=network_cli connection={}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local connection={{ cli }}"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,7 @@
---
# Use block to ensure that both cli and nxapi tests
# will run even if there are failures or errors.
- block:
- { include: cli.yaml, tags: ['cli'] }
always:
- { include: nxapi.yaml, tags: ['nxapi'] }

@ -0,0 +1,27 @@
---
- name: collect common nxapi test cases
find:
paths: "{{ role_path }}/tests/common"
patterns: "{{ testcase }}.yaml"
connection: local
register: test_cases
- name: collect nxapi test cases
find:
paths: "{{ role_path }}/tests/nxapi"
patterns: "{{ testcase }}.yaml"
connection: local
register: nxapi_cases
- set_fact:
test_cases:
files: "{{ test_cases.files }} + {{ nxapi_cases.files }}"
- name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local connection={{ nxapi }}"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

@ -0,0 +1,84 @@
---
- debug: msg="START connection={{ ansible_connection }} nxos_snmp_traps sanity test"
- debug: msg="Using provider={{ connection.transport }}"
when: ansible_connection == "local"
- name: Setup - Remove snmp_traps if configured
nxos_snmp_traps: &remove
group: all
state: disabled
provider: "{{ connection }}"
- block:
- name: Configure one snmp trap group
nxos_snmp_traps: &config
group: bridge
state: enabled
provider: "{{ connection }}"
register: result
- assert: &true
that:
- "result.changed == true"
- name: Idempotence Check
nxos_snmp_traps: *config
register: result
- assert: &false
that:
- "result.changed == false"
- name: Remove snmp trap group
nxos_snmp_traps: &rem1
group: bridge
state: disabled
provider: "{{ connection }}"
register: result
- assert: *true
- name: Idempotence Check
nxos_snmp_traps: *rem1
register: result
- assert: *false
- name: Configure all snmp trap groups
nxos_snmp_traps: &config1
group: all
state: enabled
provider: "{{ connection }}"
register: result
- assert: *true
- block:
# On I2, link command does not work properly
# On D1, callhome command does not work properly
# skip for these older platforms
- name: Idempotence Check
nxos_snmp_traps: *config1
register: result
when: imagetag is not search("I2|D1")
- assert: *false
when: imagetag is not search("I2|D1")
- name: Cleanup
nxos_snmp_traps: *remove
register: result
- assert: *true
- name: Cleanup Idempotence
nxos_snmp_traps: *remove
register: result
- assert: *false
always:
- name: Cleanup
nxos_snmp_traps: *remove
- debug: msg="END connection={{ ansible_connection }} nxos_snmp_traps sanity test"

@ -1748,7 +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_snapshot.py E325
lib/ansible/modules/network/nxos/nxos_snapshot.py E326
lib/ansible/modules/network/nxos/nxos_snmp_community.py E324
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

Loading…
Cancel
Save