From 4344132a7d094cd365fa8cb0871ad79aca185517 Mon Sep 17 00:00:00 2001 From: Nathaniel Case Date: Wed, 14 Jun 2017 11:06:49 -0400 Subject: [PATCH] nxos_vpc updates (#25452) * Add nxos_vpc tests * Split execute-show between get_config and run_commands --- lib/ansible/modules/network/nxos/nxos_vpc.py | 257 ++++++------------ .../network/nxos/fixtures/nxos_vpc/show_vpc | 20 ++ .../nxos/fixtures/nxos_vpc/show_vrf_all | 30 ++ .../modules/network/nxos/test_nxos_vpc.py | 66 +++++ 4 files changed, 204 insertions(+), 169 deletions(-) create mode 100644 test/units/modules/network/nxos/fixtures/nxos_vpc/show_vpc create mode 100644 test/units/modules/network/nxos/fixtures/nxos_vpc/show_vrf_all create mode 100644 test/units/modules/network/nxos/test_nxos_vpc.py diff --git a/lib/ansible/modules/network/nxos/nxos_vpc.py b/lib/ansible/modules/network/nxos/nxos_vpc.py index 8bbb7b5936..71fc5ddb0d 100644 --- a/lib/ansible/modules/network/nxos/nxos_vpc.py +++ b/lib/ansible/modules/network/nxos/nxos_vpc.py @@ -16,9 +16,11 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'metadata_version': '1.0', - 'status': ['preview'], - 'supported_by': 'community'} +ANSIBLE_METADATA = { + 'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community', +} DOCUMENTATION = ''' @@ -28,68 +30,68 @@ extends_documentation_fragment: nxos version_added: "2.2" short_description: Manages global VPC configuration description: - - Manages global VPC configuration + - Manages global VPC configuration author: - - Jason Edelman (@jedelman8) - - Gabriele Gerbino (@GGabriele) + - Jason Edelman (@jedelman8) + - Gabriele Gerbino (@GGabriele) notes: - - The feature vpc must be enabled before this module can be used - - If not using management vrf, vrf must be globally on the device - before using in the pkl config - - Although source IP isn't required on the command line it is - required when using this module. The PKL VRF must also be configured - prior to using this module. - - Both pkl_src and pkl_dest are needed when changing PKL VRF. + - The feature vpc must be enabled before this module can be used + - If not using management vrf, vrf must be globally on the device + before using in the pkl config + - Although source IP isn't required on the command line it is + required when using this module. The PKL VRF must also be configured + prior to using this module. + - Both pkl_src and pkl_dest are needed when changing PKL VRF. options: - domain: - description: - - VPC domain - required: true - role_priority: - description: - - Role priority for device. Remember lower is better. - required: false - default: null - system_priority: - description: - - System priority device. Remember they must match between peers. - required: false - default: null - pkl_src: - description: - - Source IP address used for peer keepalive link - required: false - default: null - pkl_dest: - description: - - Destination (remote) IP address used for peer keepalive link - required: false - default: null - pkl_vrf: - description: - - VRF used for peer keepalive link - required: false - default: management - peer_gw: - description: - - Enables/Disables peer gateway - required: true - choices: ['true','false'] - auto_recovery: - description: - - Enables/Disables auto recovery - required: true - choices: ['true','false'] - delay_restore: - description: - - manages delay restore command and config value in seconds - required: false - default: null - state: - description: - - Manages desired state of the resource - required: true - choices: ['present','absent'] + domain: + description: + - VPC domain + required: true + role_priority: + description: + - Role priority for device. Remember lower is better. + required: false + default: null + system_priority: + description: + - System priority device. Remember they must match between peers. + required: false + default: null + pkl_src: + description: + - Source IP address used for peer keepalive link + required: false + default: null + pkl_dest: + description: + - Destination (remote) IP address used for peer keepalive link + required: false + default: null + pkl_vrf: + description: + - VRF used for peer keepalive link + required: false + default: management + peer_gw: + description: + - Enables/Disables peer gateway + required: true + choices: ['true','false'] + auto_recovery: + description: + - Enables/Disables auto recovery + required: true + choices: ['true','false'] + delay_restore: + description: + - manages delay restore command and config value in seconds + required: false + default: null + state: + description: + - Manages desired state of the resource + required: true + choices: ['present','absent'] ''' EXAMPLES = ''' @@ -102,69 +104,30 @@ EXAMPLES = ''' pkl_src: 10.1.100.20 peer_gw: true auto_recovery: true - username: "{{ un }}" - password: "{{ pwd }}" - host: "{{ inventory_hostname }}" ''' RETURN = ''' -proposed: - description: k/v pairs of parameters passed into module - returned: always - type: dict - sample: {"auto_recovery": true, "domain": "100", - "peer_gw": true, "pkl_dest": "192.168.100.4", - "pkl_src": "10.1.100.20", "pkl_vrf": "management", - "role_priority": "1000", "system_priority": "2000"} -existing: - description: k/v pairs of existing VPC configuration - returned: always - type: dict - sample: {"auto_recovery": true, "delay_restore": null, - "domain": "100", "peer_gw": true, - "pkl_dest": "192.168.100.2", "pkl_src": "10.1.100.20", - "pkl_vrf": "management", "role_priority": "1000", - "system_priority": "2000"} -end_state: - description: k/v pairs of VPC configuration after module execution - returned: always - type: dict - sample: {"auto_recovery": true, "domain": "100", - "peer_gw": true, "pkl_dest": "192.168.100.4", - "pkl_src": "10.1.100.20", "pkl_vrf": "management", - "role_priority": "1000", "system_priority": "2000"} -updates: +commands: description: commands sent to the device returned: always type: list sample: ["vpc domain 100", "peer-keepalive destination 192.168.100.4 source 10.1.100.20 vrf management", "auto-recovery", "peer-gateway"] -changed: - description: check to see if a change was made on the device - returned: always - type: boolean - sample: true ''' -from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import get_config, load_config, run_commands from ansible.module_utils.nxos import nxos_argument_spec, check_args from ansible.module_utils.basic import AnsibleModule -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - if "section" not in command: - command += ' | json' - cmds = [command] - body = run_commands(module, cmds) - elif module.params['transport'] == 'nxapi': - if command_type == 'cli_show_ascii': - cmds = [command] - else: - cmds = [command + ' | json'] - body = run_commands(module, cmds) - return body +CONFIG_ARGS = { + 'role_priority': 'role priority {role_priority}', + 'system_priority': 'system-priority {system_priority}', + 'delay_restore': 'delay restore {delay_restore}', + 'peer_gw': '{peer_gw} peer-gateway', + 'auto_recovery': '{auto_recovery} auto-recovery', +} def flatten_list(command_lists): @@ -178,11 +141,9 @@ def flatten_list(command_lists): def get_vrf_list(module): - command = 'show vrf all' - vrf_table = None try: - body = execute_show_command(command, module)[0] + body = run_commands(module, ['show vrf all | json'])[0] vrf_table = body['TABLE_vrf']['ROW_vrf'] except (KeyError, AttributeError): return [] @@ -195,30 +156,13 @@ def get_vrf_list(module): return vrf_list -def get_autorecovery(auto): - auto_recovery = auto.split(' ')[0] - if 'enabled' in auto_recovery.lower(): - return True - else: - return False - - -def get_vpc_running_config(module): - command = 'show running section vpc' - body = execute_show_command(command, module, command_type='cli_show_ascii') - - return body - - def get_vpc(module): - vpc = {} + body = run_commands(module, ['show vpc | json'])[0] - command = 'show vpc' - body = execute_show_command(command, module)[0] domain = str(body['vpc-domain-id']) - auto_recovery = get_autorecovery(str( - body['vpc-auto-recovery-status'])) + auto_recovery = 'enabled' in str(body['vpc-auto-recovery-status']).lower() + vpc = {} if domain != 'not configured': delay_restore = None pkl_src = None @@ -228,7 +172,7 @@ def get_vpc(module): pkl_vrf = None peer_gw = False - run = get_vpc_running_config(module)[0] + run = get_config(module, flags=['section vpc']) if run: vpc_list = run.split('\n') for each in vpc_list: @@ -252,8 +196,7 @@ def get_vpc(module): if 'peer-gateway' in each: peer_gw = True - command = 'show vpc peer-keepalive' - body = execute_show_command(command, module)[0] + body = run_commands(module, ['show vpc peer-keepalive | json'])[0] if body: pkl_dest = body['vpc-keepalive-dest'] @@ -272,8 +215,6 @@ def get_vpc(module): vpc['pkl_dest'] = pkl_dest vpc['pkl_vrf'] = pkl_vrf vpc['peer_gw'] = peer_gw - else: - vpc = {} return vpc @@ -320,19 +261,11 @@ def get_commands_to_config_vpc(module, vpc, domain, existing): else: vpc['peer_gw'] = '' - CONFIG_ARGS = { - 'role_priority': 'role priority {role_priority}', - 'system_priority': 'system-priority {system_priority}', - 'delay_restore': 'delay restore {delay_restore}', - 'peer_gw': '{peer_gw} peer-gateway', - 'auto_recovery': '{auto_recovery} auto-recovery', - } - - for param, value in vpc.items(): - command = CONFIG_ARGS.get(param, 'DNE').format(**vpc) - if command and command != 'DNE': - commands.append(command.strip()) - command = None + for param in vpc: + command = CONFIG_ARGS.get(param) + if command is not None: + command = command.format(**vpc).strip() + commands.append(command) if commands or domain_only: commands.insert(0, 'vpc domain {0}'.format(domain)) @@ -359,9 +292,6 @@ def main(): auto_recovery=dict(required=True, type='bool'), delay_restore=dict(required=False, type='str'), state=dict(choices=['absent', 'present'], default='present'), - include_defaults=dict(default=False), - config=dict(), - save=dict(type='bool', default=False) ) argument_spec.update(nxos_argument_spec) @@ -371,6 +301,7 @@ def main(): warnings = list() check_args(module, warnings) + results = {'changed': False, 'warnings': warnings} domain = module.params['domain'] role_priority = module.params['role_priority'] @@ -407,9 +338,7 @@ def main(): 'keepalive link is not on device yet. Add it' ' first, please.') proposed = dict((k, v) for k, v in args.items() if v is not None) - changed = False existing = get_vpc(module) - end_state = existing commands = [] if state == 'present': @@ -426,25 +355,15 @@ def main(): commands.append('no vpc domain {0}'.format(domain)) cmds = flatten_list(commands) + results['commands'] = cmds if cmds: - if module.check_mode: - module.exit_json(changed=True, commands=cmds) - else: - changed = True + results['changed'] = True + if not module.check_mode: load_config(module, cmds) - end_state = get_vpc(module) if 'configure' in cmds: cmds.pop(0) - results = {} - results['proposed'] = proposed - results['existing'] = existing - results['end_state'] = end_state - results['updates'] = cmds - results['changed'] = changed - results['warnings'] = warnings - module.exit_json(**results) diff --git a/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vpc b/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vpc new file mode 100644 index 0000000000..7d2c2eaeee --- /dev/null +++ b/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vpc @@ -0,0 +1,20 @@ +{ + "vpc-domain-id": "not configured", + "vpc-peer-status": "peer-not-configured", + "vpc-peer-status-reason": "SUCCESS", + "vpc-peer-keepalive-status": "disabled", + "vpc-peer-consistency": "inconsistent", + "vpc-peer-consistency-status": "SYSERR_MCECM_MCT_DOES_NOT_EXISTS", + "vpc-per-vlan-peer-consistency": "inconsistent", + "vpc-type-2-consistency": "inconsistent", + "vpc-type-2-consistency-status": "SYSERR_MCECM_MCT_DOES_NOT_EXISTS", + "vpc-role": "none-established", + "num-of-vpcs": "0", + "peer-gateway": "disabled", + "dual-active-excluded-vlans": "-", + "vpc-graceful-consistency-check-status": "enabled", + "vpc-auto-recovery-status": "Enabled (timeout = 240 seconds)", + "operational-l3-peer": "disabled", + "vpc-isolation-status": "disabled-user", + "vpc-check-consist-note": "disabled" +} diff --git a/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vrf_all b/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vrf_all new file mode 100644 index 0000000000..838190fb71 --- /dev/null +++ b/test/units/modules/network/nxos/fixtures/nxos_vpc/show_vrf_all @@ -0,0 +1,30 @@ +{ + "TABLE_vrf": { + "ROW_vrf": [ + { + "vrf_name": "coke", + "vrf_id": 4, + "vrf_state": "Up", + "vrf_reason": "--" + }, + { + "vrf_name": "default", + "vrf_id": 1, + "vrf_state": "Up", + "vrf_reason": "--" + }, + { + "vrf_name": "management", + "vrf_id": 2, + "vrf_state": "Up", + "vrf_reason": "--" + }, + { + "vrf_name": "test-vrf", + "vrf_id": 3, + "vrf_state": "Up", + "vrf_reason": "--" + } + ] + } +} diff --git a/test/units/modules/network/nxos/test_nxos_vpc.py b/test/units/modules/network/nxos/test_nxos_vpc.py new file mode 100644 index 0000000000..a3126fa831 --- /dev/null +++ b/test/units/modules/network/nxos/test_nxos_vpc.py @@ -0,0 +1,66 @@ +# (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 . + +# Make coding more python3-ish +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os + +from ansible.compat.tests.mock import patch +from ansible.modules.network.nxos import nxos_vpc +from .nxos_module import TestNxosModule, load_fixture, set_module_args + + +class TestNxosVpcModule(TestNxosModule): + + module = nxos_vpc + + def setUp(self): + self.mock_load_config = patch('ansible.modules.network.nxos.nxos_vpc.load_config') + self.load_config = self.mock_load_config.start() + + self.mock_run_commands = patch('ansible.modules.network.nxos.nxos_vpc.run_commands') + self.run_commands = self.mock_run_commands.start() + + def tearDown(self): + self.mock_load_config.stop() + self.mock_run_commands.stop() + + def load_fixtures(self, commands=None): + def load_from_file(*args, **kwargs): + module, commands = args + output = list() + + for command in commands: + filename = str(command).split(' | ')[0].replace(' ', '_') + filename = os.path.join('nxos_vpc', filename) + output.append(load_fixture(filename)) + return output + + self.load_config.return_value = None + self.run_commands.side_effect = load_from_file + + def test_nxos_vpc_present(self): + set_module_args(dict(domain=100, role_priority=32667, system_priority=2000, + pkl_dest='192.168.100.4', pkl_src='10.1.100.20', + peer_gw=True, auto_recovery=True)) + self.execute_module(changed=True, commands=[ + 'vpc domain 100', 'role priority 32667', 'system-priority 2000', + 'peer-keepalive destination 192.168.100.4 source 10.1.100.20 vrf management', + 'peer-gateway', 'auto-recovery', + ])