nxos_acl fixes (#23915)

* Update nxos_acl

* unit tests for nxos_acl

* Remove nxos_acl from pep8-legacy
This commit is contained in:
Nathaniel Case 2017-04-26 16:29:53 -04:00 committed by GitHub
parent bffccb5396
commit f0914ee3c2
4 changed files with 510 additions and 249 deletions

View file

@ -16,9 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
ANSIBLE_METADATA = {'metadata_version': '1.0', ANSIBLE_METADATA = {
'status': ['preview'], 'metadata_version': '1.0',
'supported_by': 'community'} 'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = ''' DOCUMENTATION = '''
@ -28,179 +30,178 @@ extends_documentation_fragment: nxos
version_added: "2.2" version_added: "2.2"
short_description: Manages access list entries for ACLs. short_description: Manages access list entries for ACLs.
description: description:
- Manages access list entries for ACLs. - Manages access list entries for ACLs.
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
- C(state=absent) removes the ACE if it exists. - C(state=absent) removes the ACE if it exists.
- C(state=delete_acl) deleted the ACL if it exists. - C(state=delete_acl) deletes the ACL if it exists.
- For idempotency, use port numbers for the src/dest port - For idempotency, use port numbers for the src/dest port
params like I(src_port1) and names for the well defined protocols params like I(src_port1) and names for the well defined protocols
for the I(proto) param. for the I(proto) param.
- Although this module is idempotent in that if the ace as presented in - Although this module is idempotent in that if the ace as presented in
the task is identical to the one on the switch, no changes will be made. the task is identical to the one on the switch, no changes will be made.
If there is any difference, what is in Ansible will be pushed (configured If there is any difference, what is in Ansible will be pushed (configured
options will be overridden). This is to improve security, but at the options will be overridden). This is to improve security, but at the
same time remember an ACE is removed, then re-added, so if there is a same time remember an ACE is removed, then re-added, so if there is a
change, the new ACE will be exactly what parameters you are sending to change, the new ACE will be exactly what parameters you are sending to
the module. the module.
options: options:
seq: seq:
description: description:
- Sequence number of the entry (ACE). - Sequence number of the entry (ACE).
required: false required: false
default: null default: null
name: name:
description: description:
- Case sensitive name of the access list (ACL). - Case sensitive name of the access list (ACL).
required: true required: true
action: action:
description: description:
- Action of the ACE. - Action of the ACE.
required: false required: false
default: null default: null
choices: ['permit', 'deny', 'remark'] choices: ['permit', 'deny', 'remark']
remark: remark:
description: description:
- If action is set to remark, this is the description. - If action is set to remark, this is the description.
required: false required: false
default: null default: null
proto: proto:
description: description:
- Port number or protocol (as supported by the switch). - Port number or protocol (as supported by the switch).
required: false required: false
default: null default: null
src: src:
description: description:
- Source ip and mask using IP/MASK notation and - Source ip and mask using IP/MASK notation and
supports keyword 'any'. supports keyword 'any'.
required: false required: false
default: null default: null
src_port_op: src_port_op:
description: description:
- Source port operands such as eq, neq, gt, lt, range. - Source port operands such as eq, neq, gt, lt, range.
required: false required: false
default: null default: null
choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range'] choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range']
src_port1: src_port1:
description: description:
- Port/protocol and also first (lower) port when using range - Port/protocol and also first (lower) port when using range
operand. operand.
required: false required: false
default: null default: null
src_port2: src_port2:
description: description:
- Second (end) port when using range operand. - Second (end) port when using range operand.
required: false required: false
default: null default: null
dest: dest:
description: description:
- Destination ip and mask using IP/MASK notation and supports the - Destination ip and mask using IP/MASK notation and supports the
keyword 'any'. keyword 'any'.
required: false required: false
default: null default: null
dest_port_op: dest_port_op:
description: description:
- Destination port operands such as eq, neq, gt, lt, range. - Destination port operands such as eq, neq, gt, lt, range.
required: false required: false
default: null default: null
choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range'] choices: ['any', 'eq', 'gt', 'lt', 'neq', 'range']
dest_port1: dest_port1:
description: description:
- Port/protocol and also first (lower) port when using range - Port/protocol and also first (lower) port when using range
operand. operand.
required: false required: false
default: null default: null
dest_port2: dest_port2:
description: description:
- Second (end) port when using range operand. - Second (end) port when using range operand.
required: false required: false
default: null default: null
log: log:
description: description:
- Log matches against this entry. - Log matches against this entry.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
urg: urg:
description: description:
- Match on the URG bit. - Match on the URG bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
ack: ack:
description: description:
- Match on the ACK bit. - Match on the ACK bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
psh: psh:
description: description:
- Match on the PSH bit. - Match on the PSH bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
rst: rst:
description: description:
- Match on the RST bit. - Match on the RST bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
syn: syn:
description: description:
- Match on the SYN bit. - Match on the SYN bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
fin: fin:
description: description:
- Match on the FIN bit. - Match on the FIN bit.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
established: established:
description: description:
- Match established connections. - Match established connections.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
fragments: fragments:
description: description:
- Check non-initial fragments. - Check non-initial fragments.
required: false required: false
default: null default: null
choices: ['enable'] choices: ['enable']
time-range: time-range:
description: description:
- Name of time-range to apply. - Name of time-range to apply.
required: false required: false
default: null default: null
precedence: precedence:
description: description:
- Match packets with given precedence. - Match packets with given precedence.
required: false required: false
default: null default: null
choices: ['critical', 'flash', 'flash-override', 'immediate', choices: ['critical', 'flash', 'flash-override', 'immediate',
'internet', 'network', 'priority', 'routine'] 'internet', 'network', 'priority', 'routine']
dscp: dscp:
description: description:
- Match packets with given dscp value. - Match packets with given dscp value.
required: false required: false
default: null default: null
choices: ['af11', 'af12', 'af13', 'af21', 'af22', 'af23','af31','af32', choices: ['af11', 'af12', 'af13', 'af21', 'af22', 'af23','af31','af32',
'af33', 'af41', 'af42', 'af43', 'cs1', 'cs2', 'cs3', 'cs4', 'af33', 'af41', 'af42', 'af43', 'cs1', 'cs2', 'cs3', 'cs4',
'cs5', 'cs6', 'cs7', 'default', 'ef'] 'cs5', 'cs6', 'cs7', 'default', 'ef']
state: state:
description: description:
- Specify desired state of the resource. - Specify desired state of the resource.
required: false required: false
default: present default: present
choices: ['present','absent','delete_acl'] choices: ['present','absent','delete_acl']
''' '''
EXAMPLES = ''' EXAMPLES = '''
# configure ACL ANSIBLE # configure ACL ANSIBLE
- nxos_acl: - nxos_acl:
name: ANSIBLE name: ANSIBLE
@ -214,49 +215,22 @@ EXAMPLES = '''
''' '''
RETURN = ''' RETURN = '''
proposed: commands:
description: k/v pairs of parameters passed into module.
returned: always
type: dict
sample: {"action": "permit", "dest": "any", "name": "ANSIBLE",
"proto": "tcp", "seq": "10", "src": "1.1.1.1/24"}
existing:
description: k/v pairs of existing ACL entries.
returned: always
type: dict
sample: {}
end_state:
description: k/v pairs of ACL entries after module execution.
returned: always
type: dict
sample: {"action": "permit", "dest": "any", "name": "ANSIBLE",
"proto": "tcp", "seq": "10", "src": "1.1.1.1/24"}
updates:
description: commands sent to the device description: commands sent to the device
returned: always returned: always
type: list type: list
sample: ["ip access-list ANSIBLE", "10 permit tcp 1.1.1.1/24 any"] sample: ["ip access-list ANSIBLE", "10 permit tcp 1.1.1.1/24 any"]
changed:
description: check to see if a change was made on the device
returned: always
type: boolean
sample: true
''' '''
import re
from ansible.module_utils.nxos import load_config, run_commands from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.nxos import nxos_argument_spec, check_args from ansible.module_utils.nxos import nxos_argument_spec, check_args
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):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
body = run_commands(module, cmds) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi':
cmds = [command]
body = run_commands(module, cmds)
return body return body
@ -264,7 +238,6 @@ def get_acl(module, acl_name, seq_number):
command = 'show ip access-list' command = 'show ip access-list'
new_acl = [] new_acl = []
saveme = {} saveme = {}
seqs = []
acl_body = {} acl_body = {}
body = execute_show_command(command, module)[0] body = execute_show_command(command, module)[0]
@ -278,18 +251,19 @@ def get_acl(module, acl_name, seq_number):
acl_entries = acl_body['TABLE_seqno']['ROW_seqno'] acl_entries = acl_body['TABLE_seqno']['ROW_seqno']
acl_name = acl_body.get('acl_name') acl_name = acl_body.get('acl_name')
except KeyError: # could be raised if no ACEs are configured for an ACL except KeyError: # could be raised if no ACEs are configured for an ACL
return saveme, [{'acl': 'no_entries'}], seqs return {}, [{'acl': 'no_entries'}]
if isinstance(acl_entries, dict): if isinstance(acl_entries, dict):
acl_entries = [acl_entries] acl_entries = [acl_entries]
for each in acl_entries: for each in acl_entries:
temp = collections.OrderedDict() temp = {}
keep = {} options = {}
remark = each.get('remark')
temp['name'] = acl_name temp['name'] = acl_name
temp['seq'] = str(each.get('seqno')) temp['seq'] = str(each.get('seqno'))
temp['options'] = {}
remark = each.get('remark')
if remark: if remark:
temp['remark'] = remark temp['remark'] = remark
temp['action'] = 'remark' temp['action'] = 'remark'
@ -305,7 +279,6 @@ def get_acl(module, acl_name, seq_number):
temp['dest_port1'] = each.get('dest_port1_num') temp['dest_port1'] = each.get('dest_port1_num')
temp['dest_port2'] = each.get('dest_port2_num') temp['dest_port2'] = each.get('dest_port2_num')
options = collections.OrderedDict()
options['log'] = each.get('log') options['log'] = each.get('log')
options['urg'] = each.get('urg') options['urg'] = each.get('urg')
options['ack'] = each.get('ack') options['ack'] = each.get('ack')
@ -319,27 +292,23 @@ def get_acl(module, acl_name, seq_number):
options['fragments'] = each.get('fragments') options['fragments'] = each.get('fragments')
options['time_range'] = each.get('timerange') options['time_range'] = each.get('timerange')
options_no_null = {} keep = {}
for key, value in options.items():
if value is not None:
options_no_null[key] = value
keep['options'] = options_no_null
for key, value in temp.items(): for key, value in temp.items():
if value: if value:
keep[key] = value keep[key] = value
# ensure options is always in the dict
if keep.get('options', 'DNE') == 'DNE': options_no_null = {}
keep['options'] = {} for key, value in options.items():
if value is not None:
options_no_null[key] = value
keep['options'] = options_no_null
if keep.get('seq') == seq_number: if keep.get('seq') == seq_number:
saveme = dict(keep) saveme = dict(keep)
seqs.append(str(keep.get('seq')))
new_acl.append(keep) new_acl.append(keep)
return saveme, new_acl, seqs return saveme, new_acl
def _acl_operand(operand, srcp1, sprcp2): def _acl_operand(operand, srcp1, sprcp2):
@ -442,18 +411,17 @@ def main():
established=dict(required=False, choices=['enable']), established=dict(required=False, choices=['enable']),
time_range=dict(required=False), time_range=dict(required=False),
precedence=dict(required=False, choices=['critical', 'flash', precedence=dict(required=False, choices=['critical', 'flash',
'flash-override', 'flash-override',
'immediate', 'internet', 'immediate', 'internet',
'network', 'priority', 'network', 'priority',
'routine']), 'routine']),
dscp=dict(required=False, choices=['af11', 'af12', 'af13', 'af21', dscp=dict(required=False, choices=['af11', 'af12', 'af13', 'af21',
'af22', 'af23', 'af31', 'af32', 'af22', 'af23', 'af31', 'af32',
'af33', 'af41', 'af42', 'af43', 'af33', 'af41', 'af42', 'af43',
'cs1', 'cs2', 'cs3', 'cs4', 'cs1', 'cs2', 'cs3', 'cs4',
'cs5', 'cs6', 'cs7', 'default', 'cs5', 'cs6', 'cs7', 'default',
'ef']), 'ef']),
state=dict(choices=['absent', 'present', 'delete_acl'], state=dict(choices=['absent', 'present', 'delete_acl'], default='present'),
default='present'),
protocol=dict(choices=['http', 'https'], default='http'), protocol=dict(choices=['http', 'https'], default='http'),
host=dict(required=True), host=dict(required=True),
username=dict(type='str'), username=dict(type='str'),
@ -466,11 +434,12 @@ def main():
argument_spec.update(nxos_argument_spec) argument_spec.update(nxos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)
warnings = list() warnings = list()
check_args(module, warnings) check_args(module, warnings)
results = dict(changed=False, warnings=warnings)
state = module.params['state'] state = module.params['state']
action = module.params['action'] action = module.params['action']
@ -482,8 +451,7 @@ def main():
seq = module.params['seq'] seq = module.params['seq']
if action == 'remark' and not remark: if action == 'remark' and not remark:
module.fail_json(msg='when state is action, remark param is also ' module.fail_json(msg='when state is action, remark param is also required')
'required')
REQUIRED = ['seq', 'name', 'action', 'proto', 'src', 'dest'] REQUIRED = ['seq', 'name', 'action', 'proto', 'src', 'dest']
ABSENT = ['name', 'seq'] ABSENT = ['name', 'seq']
@ -530,14 +498,12 @@ def main():
existing_options = {} existing_options = {}
# getting existing existing_core=dict, acl=list, seq=list # getting existing existing_core=dict, acl=list, seq=list
existing_core, acl, seqs = get_acl(module, name, seq) existing_core, acl = get_acl(module, name, seq)
if existing_core: if existing_core:
existing_options = existing_core.get('options') existing_options = existing_core.get('options')
existing_core.pop('options') existing_core.pop('options')
end_state = acl
commands = [] commands = []
changed = False
delta_core = {} delta_core = {}
delta_options = {} delta_options = {}
@ -545,7 +511,7 @@ def main():
delta_core = dict( delta_core = dict(
set(proposed_core.items()).difference( set(proposed_core.items()).difference(
existing_core.items()) existing_core.items())
) )
delta_options = dict( delta_options = dict(
set(proposed_options.items()).difference( set(proposed_options.items()).difference(
existing_options.items()) existing_options.items())
@ -569,7 +535,6 @@ def main():
if acl[0].get('acl') != 'no_entries': if acl[0].get('acl') != 'no_entries':
commands.append(['no ip access-list {0}'.format(name)]) commands.append(['no ip access-list {0}'.format(name)])
results = {}
cmds = [] cmds = []
if commands: if commands:
preface = [] preface = []
@ -582,21 +547,14 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
load_config(module, cmds) load_config(module, cmds)
changed = True results['changed'] = True
new_existing_core, end_state, seqs = get_acl(module, name, seq)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
results['proposed'] = proposed results['commands'] = cmds
results['existing'] = existing_core
results['changed'] = changed
results['warnings'] = warnings
results['updates'] = cmds
results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -541,7 +541,6 @@ lib/ansible/modules/network/nxos/_nxos_mtu.py
lib/ansible/modules/network/nxos/_nxos_template.py lib/ansible/modules/network/nxos/_nxos_template.py
lib/ansible/modules/network/nxos/nxos_aaa_server.py lib/ansible/modules/network/nxos/nxos_aaa_server.py
lib/ansible/modules/network/nxos/nxos_aaa_server_host.py lib/ansible/modules/network/nxos/nxos_aaa_server_host.py
lib/ansible/modules/network/nxos/nxos_acl.py
lib/ansible/modules/network/nxos/nxos_acl_interface.py lib/ansible/modules/network/nxos/nxos_acl_interface.py
lib/ansible/modules/network/nxos/nxos_bgp.py lib/ansible/modules/network/nxos/nxos_bgp.py
lib/ansible/modules/network/nxos/nxos_bgp_af.py lib/ansible/modules/network/nxos/nxos_bgp_af.py

View file

@ -0,0 +1,227 @@
{
"TABLE_ip_ipv6_mac": {
"ROW_ip_ipv6_mac": [
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-bgp",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"src_port_op": "gt",
"src_port1_num": "1024",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_str": "bgp",
"dest_port1_num": "179"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_str": "bgp",
"src_port1_num": "179",
"dest_any": "any",
"dest_port_op": "gt",
"dest_port1_num": "1024"
}
]
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-cts",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_num": "64999"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_num": "64999",
"dest_any": "any"
}
]
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-dhcp",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_str": "bootpc",
"src_port1_num": "68",
"dest_any": "any"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"src_port_op": "neq",
"src_port1_str": "bootps",
"src_port1_num": "67",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_str": "bootps",
"dest_port1_num": "67"
}
]
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-dhcp-relay-response",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_str": "bootps",
"src_port1_num": "67",
"dest_any": "any"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_str": "bootpc",
"dest_port1_num": "68"
}
]
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-eigrp",
"TABLE_seqno": {
"ROW_seqno": {
"seqno": 10,
"permitdeny": "permit",
"proto_str": "eigrp",
"src_any": "any",
"dest_any": "any"
}
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-ftp",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_str": "ftp-data",
"dest_port1_num": "20"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"dest_any": "any",
"dest_port_op": "eq",
"dest_port1_str": "ftp",
"dest_port1_num": "21"
},
{
"seqno": 30,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_str": "ftp-data",
"src_port1_num": "20",
"dest_any": "any"
},
{
"seqno": 40,
"permitdeny": "permit",
"proto_str": "tcp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_str": "ftp",
"src_port1_num": "21",
"dest_any": "any"
}
]
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-glbp",
"TABLE_seqno": {
"ROW_seqno": {
"seqno": 10,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"src_port_op": "eq",
"src_port1_num": "3222",
"dest_ip_prefix": "224.0.0.0/24",
"dest_port_op": "eq",
"dest_port1_num": "3222"
}
}
},
{
"op_ip_ipv6_mac": "ip",
"acl_name": "copp-system-p-acl-hsrp",
"TABLE_seqno": {
"ROW_seqno": [
{
"seqno": 10,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"dest_ip_prefix": "224.0.0.2/32",
"dest_port_op": "eq",
"dest_port1_num": "1985"
},
{
"seqno": 20,
"permitdeny": "permit",
"proto_str": "udp",
"src_any": "any",
"dest_ip_prefix": "224.0.0.102/32",
"dest_port_op": "eq",
"dest_port1_num": "1985"
}
]
}
}
]
}
}

View file

@ -0,0 +1,77 @@
# (c) 2016 Red Hat Inc.
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.compat.tests.mock import patch
from ansible.modules.network.nxos import nxos_acl
from .nxos_module import TestNxosModule, load_fixture, set_module_args
class TestNxosAclModule(TestNxosModule):
module = nxos_acl
def setUp(self):
self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_acl.run_commands')
self.run_commands = self.mock_run_commands.start()
self.mock_load_config = patch('ansible.modules.network.nxos.nxos_acl.load_config')
self.load_config = self.mock_load_config.start()
def tearDown(self):
self.mock_run_commands.stop()
self.mock_load_config.stop()
def load_fixtures(self, commands=None):
def load_from_file(*args, **kwargs):
module, commands = args
output = list()
for item in commands:
try:
obj = json.loads(item)
command = obj['command']
except ValueError:
command = item
filename = str(command).split(' | ')[0].replace(' ', '_')
filename = 'nxos_acl/%s.txt' % filename
output.append(load_fixture(filename))
return output
self.run_commands.side_effect = load_from_file
self.load_config.return_value = None
def test_nxos_acl(self):
set_module_args(dict(name='ANSIBLE', seq=10, action='permit',
proto='tcp', src='1.1.1.1/24', dest='any'))
result = self.execute_module(changed=True)
self.assertEqual(result['commands'], ['ip access-list ANSIBLE', '10 permit tcp 1.1.1.1/24 any'])
def test_nxos_acl_remove(self):
set_module_args(dict(name='copp-system-p-acl-bgp', seq=10, state='absent'))
result = self.execute_module(changed=True)
self.assertEqual(result['commands'], ['ip access-list copp-system-p-acl-bgp', 'no 10'])
def test_nxos_acl_delete_acl(self):
set_module_args(dict(name='copp-system-p-acl-bgp', state='delete_acl'))
result = self.execute_module(changed=True)
self.assertEqual(result['commands'], ['no ip access-list copp-system-p-acl-bgp'])