From 21d993a4b8e26f85ebb136330243ad523ad9ba3c Mon Sep 17 00:00:00 2001 From: Peter Sprygada Date: Wed, 15 Feb 2017 11:43:09 -0500 Subject: [PATCH] refactors nxos module to use persistent connections (#21470) This completes the refactor of the nxos modules to use the persistent connection. It also updates all of the nxos modules to use the new connection module and preserves use of nxapi as well. --- lib/ansible/module_utils/netcfg.py | 89 ++++ lib/ansible/module_utils/nxos.py | 459 ++++++++++-------- lib/ansible/module_utils/nxos_cli.py | 157 ------ .../modules/network/nxos/nxos_aaa_server.py | 225 +-------- .../network/nxos/nxos_aaa_server_host.py | 250 +--------- lib/ansible/modules/network/nxos/nxos_acl.py | 248 +--------- .../network/nxos/nxos_acl_interface.py | 248 +--------- lib/ansible/modules/network/nxos/nxos_bgp.py | 164 +------ .../modules/network/nxos/nxos_bgp_af.py | 165 +------ .../modules/network/nxos/nxos_bgp_neighbor.py | 164 +------ .../network/nxos/nxos_bgp_neighbor_af.py | 164 +------ .../modules/network/nxos/nxos_command.py | 169 +++---- .../modules/network/nxos/nxos_config.py | 65 +-- .../modules/network/nxos/nxos_evpn_global.py | 166 +------ .../modules/network/nxos/nxos_evpn_vni.py | 164 +------ .../modules/network/nxos/nxos_facts.py | 143 +++--- .../modules/network/nxos/nxos_feature.py | 256 +--------- .../modules/network/nxos/nxos_file_copy.py | 215 +------- lib/ansible/modules/network/nxos/nxos_gir.py | 225 +-------- .../nxos/nxos_gir_profile_management.py | 189 +------- lib/ansible/modules/network/nxos/nxos_hsrp.py | 244 +--------- lib/ansible/modules/network/nxos/nxos_igmp.py | 169 +------ .../network/nxos/nxos_igmp_interface.py | 248 +--------- .../network/nxos/nxos_igmp_snooping.py | 250 +--------- .../modules/network/nxos/nxos_install_os.py | 223 +-------- .../modules/network/nxos/nxos_interface.py | 249 +--------- .../network/nxos/nxos_interface_ospf.py | 165 +------ .../modules/network/nxos/nxos_ip_interface.py | 247 +--------- lib/ansible/modules/network/nxos/nxos_mtu.py | 253 +--------- lib/ansible/modules/network/nxos/nxos_ntp.py | 246 +--------- .../modules/network/nxos/nxos_ntp_auth.py | 246 +--------- .../modules/network/nxos/nxos_ntp_options.py | 247 +--------- .../modules/network/nxos/nxos_nxapi.py | 300 +++++------- lib/ansible/modules/network/nxos/nxos_ospf.py | 164 +------ .../modules/network/nxos/nxos_ospf_vrf.py | 164 +------ .../network/nxos/nxos_overlay_global.py | 182 +------ lib/ansible/modules/network/nxos/nxos_pim.py | 167 +------ .../network/nxos/nxos_pim_interface.py | 248 +--------- .../network/nxos/nxos_pim_rp_address.py | 167 +------ lib/ansible/modules/network/nxos/nxos_ping.py | 214 +------- .../modules/network/nxos/nxos_portchannel.py | 237 +-------- .../modules/network/nxos/nxos_reboot.py | 247 +--------- .../modules/network/nxos/nxos_rollback.py | 163 +------ lib/ansible/modules/network/nxos/nxos_smu.py | 226 +-------- .../modules/network/nxos/nxos_snapshot.py | 224 +-------- .../network/nxos/nxos_snmp_community.py | 248 +--------- .../modules/network/nxos/nxos_snmp_contact.py | 248 +--------- .../modules/network/nxos/nxos_snmp_host.py | 248 +--------- .../network/nxos/nxos_snmp_location.py | 248 +--------- .../modules/network/nxos/nxos_snmp_traps.py | 248 +--------- .../modules/network/nxos/nxos_snmp_user.py | 248 +--------- .../modules/network/nxos/nxos_static_route.py | 173 +------ .../modules/network/nxos/nxos_switchport.py | 248 +--------- lib/ansible/modules/network/nxos/nxos_udld.py | 248 +--------- .../network/nxos/nxos_udld_interface.py | 248 +--------- lib/ansible/modules/network/nxos/nxos_user.py | 357 ++++++++++++++ lib/ansible/modules/network/nxos/nxos_vlan.py | 287 ++--------- lib/ansible/modules/network/nxos/nxos_vpc.py | 248 +--------- .../network/nxos/nxos_vpc_interface.py | 247 +--------- lib/ansible/modules/network/nxos/nxos_vrf.py | 247 +--------- .../modules/network/nxos/nxos_vrf_af.py | 166 +------ .../network/nxos/nxos_vrf_interface.py | 240 +-------- lib/ansible/modules/network/nxos/nxos_vrrp.py | 250 +--------- .../modules/network/nxos/nxos_vtp_domain.py | 247 +--------- .../modules/network/nxos/nxos_vtp_password.py | 247 +--------- .../modules/network/nxos/nxos_vtp_version.py | 248 +--------- .../modules/network/nxos/nxos_vxlan_vtep.py | 167 +------ .../network/nxos/nxos_vxlan_vtep_vni.py | 167 +------ lib/ansible/plugins/action/nxos.py | 112 +++++ lib/ansible/plugins/action/nxos_config.py | 93 +++- lib/ansible/plugins/action/nxos_template.py | 83 +++- lib/ansible/plugins/terminal/nxos.py | 8 - 72 files changed, 2301 insertions(+), 12933 deletions(-) delete mode 100644 lib/ansible/module_utils/nxos_cli.py create mode 100644 lib/ansible/modules/network/nxos/nxos_user.py create mode 100644 lib/ansible/plugins/action/nxos.py diff --git a/lib/ansible/module_utils/netcfg.py b/lib/ansible/module_utils/netcfg.py index 90180085e3..abdbffd784 100644 --- a/lib/ansible/module_utils/netcfg.py +++ b/lib/ansible/module_utils/netcfg.py @@ -28,6 +28,7 @@ import re from ansible.module_utils.six.moves import zip +from ansible.module_utils.network_common import to_list DEFAULT_COMMENT_TOKENS = ['#', '!', '/*', '*/'] @@ -361,3 +362,91 @@ class NetworkConfig(object): self.items.append(item) +class CustomNetworkConfig(NetworkConfig): + + def expand_section(self, configobj, S=None): + if S is None: + S = list() + S.append(configobj) + for child in configobj.children: + if child in S: + continue + self.expand_section(child, S) + return S + + def get_object(self, path): + for item in self.items: + if item.text == path[-1]: + parents = [p.text for p in item.parents] + if parents == path[:-1]: + return item + + def to_block(self, section): + return '\n'.join([item.raw for item in section]) + + def get_section(self, path): + try: + section = self.get_section_objects(path) + return self.to_block(section) + except ValueError: + return list() + + def get_section_objects(self, path): + if not isinstance(path, list): + path = [path] + obj = self.get_object(path) + if not obj: + raise ValueError('path does not exist in config') + return self.expand_section(obj) + + + def add(self, lines, parents=None): + """Adds one or lines of configuration + """ + + ancestors = list() + offset = 0 + obj = None + + ## global config command + if not parents: + for line in to_list(lines): + item = ConfigLine(line) + item.raw = line + if item not in self.items: + self.items.append(item) + + else: + for index, p in enumerate(parents): + try: + i = index + 1 + obj = self.get_section_objects(parents[:i])[0] + ancestors.append(obj) + + except ValueError: + # add parent to config + offset = index * self.indent + obj = ConfigLine(p) + obj.raw = p.rjust(len(p) + offset) + if ancestors: + obj.parents = list(ancestors) + ancestors[-1].children.append(obj) + self.items.append(obj) + ancestors.append(obj) + + # add child objects + for line in to_list(lines): + # check if child already exists + for child in ancestors[-1].children: + if child.text == line: + break + else: + offset = len(parents) * self.indent + item = ConfigLine(line) + item.raw = line.rjust(len(line) + offset) + item.parents = ancestors + ancestors[-1].children.append(item) + self.items.append(item) + + + diff --git a/lib/ansible/module_utils/nxos.py b/lib/ansible/module_utils/nxos.py index 0360747d89..fa24e0b411 100644 --- a/lib/ansible/module_utils/nxos.py +++ b/lib/ansible/module_utils/nxos.py @@ -1,80 +1,150 @@ # -# (c) 2015 Peter Sprygada, +# This code is part of Ansible, but is an independent component. # -# This file is part of Ansible +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. # -# 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. +# (c) 2017 Red Hat, Inc. # -# 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. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: # -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # - import re -import time import collections -from ansible.module_utils.basic import json, json_dict_bytes_to_unicode -from ansible.module_utils.network import ModuleStub, NetworkError, NetworkModule -from ansible.module_utils.network import add_argument, register_transport, to_list -from ansible.module_utils.shell import CliBase -from ansible.module_utils.urls import fetch_url, url_argument_spec +from ansible.module_utils.basic import env_fallback +from ansible.module_utils.network_common import to_list, ComplexList +from ansible.module_utils.connection import exec_command +from ansible.module_utils.six import iteritems +from ansible.module_utils.urls import fetch_url -add_argument('use_ssl', dict(default=False, type='bool')) -add_argument('validate_certs', dict(default=True, type='bool')) +_DEVICE_CONNECTION = None -class NxapiConfigMixin(object): +nxos_argument_spec = { + 'host': dict(), + 'port': dict(type='int'), + 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), + 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), + 'use_ssl': dict(type='bool'), + 'validate_certs': dict(type='bool'), + 'timeout': dict(type='int'), + 'provider': dict(type='dict'), + 'transport': dict(choices=['cli', 'nxapi']) +} - def get_config(self, include_defaults=False, **kwargs): - cmd = 'show running-config' - if include_defaults: - cmd += ' all' - if isinstance(self, Nxapi): - return self.execute([cmd], output='text')[0] - else: - return self.execute([cmd])[0] +def check_args(module, warnings): + provider = module.params['provider'] or {} + for key in nxos_argument_spec: + if key not in ['provider', 'transport'] and module.params[key]: + warnings.append('argument %s has been deprecated and will be ' + 'removed in a future version' % key) + +def load_params(module): + provider = module.params.get('provider') or dict() + for key, value in iteritems(provider): + if key in nxos_argument_spec: + if module.params.get(key) is None and value is not None: + module.params[key] = value + +def get_connection(module): + global _DEVICE_CONNECTION + if not _DEVICE_CONNECTION: + load_params(module) + transport = module.params['transport'] + if transport == 'cli': + conn = Cli(module) + elif transport == 'nxapi': + conn = Nxapi(module) + _DEVICE_CONNECTION = conn + return _DEVICE_CONNECTION + +class Cli: + + def __init__(self, module): + self._module = module + self._device_configs = {} + + def exec_command(self, command): + if isinstance(command, dict): + command = self._module.jsonify(command) + return exec_command(self._module, command) + + def get_config(self, flags=[]): + """Retrieves the current config from the device or cache + """ + cmd = 'show running-config ' + cmd += ' '.join(flags) + cmd = cmd.strip() + + try: + return self._device_configs[cmd] + except KeyError: + rc, out, err = self.exec_command(cmd) + if rc != 0: + self._module.fail_json(msg=err) + cfg = str(out).strip() + self._device_configs[cmd] = cfg + return cfg + + def run_commands(self, commands, check_rc=True): + """Run list of commands on remote device and return results + """ + responses = list() + + for item in to_list(commands): + if item['output'] == 'json' and not is_json(item['command']): + cmd = '%s | json' % item['command'] + elif item['output'] == 'text' and is_json(item['command']): + cmd = item['command'].split('|')[0] + else: + cmd = item['command'] + + rc, out, err = self.exec_command(cmd) + + if check_rc and rc != 0: + self._module.fail_json(msg=err) + + try: + out = self._module.from_json(out) + except ValueError: + out = str(out).strip() + + responses.append(out) + return responses def load_config(self, config): - checkpoint = 'ansible_%s' % int(time.time()) - try: - self.execute(['checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['checkpoint %s' % checkpoint]) + """Sends configuration commands to the remote device + """ + rc, out, err = self.exec_command('configure') + if rc != 0: + self._module.fail_json(msg='unable to enter configuration mode', output=err) - try: - self.configure(config) - except NetworkError: - self.load_checkpoint(checkpoint) - raise + for cmd in config: + rc, out, err = self.exec_command(cmd) + if rc != 0: + self._module.fail_json(msg=err) - try: - self.execute(['no checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['no checkpoint %s' % checkpoint]) + self.exec_command('end') - def save_config(self, **kwargs): - try: - self.execute(['copy running-config startup-config'], output='text') - except TypeError: - self.execute(['copy running-config startup-config']) - - def load_checkpoint(self, checkpoint): - try: - self.execute(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint]) - - -class Nxapi(NxapiConfigMixin): +class Nxapi: OUTPUT_TO_COMMAND_TYPE = { 'text': 'cli_show_ascii', @@ -83,20 +153,33 @@ class Nxapi(NxapiConfigMixin): 'config': 'cli_conf' } - def __init__(self): - self.url = None - self.url_args = ModuleStub(url_argument_spec(), self._error) + def __init__(self, module): + self._module = module self._nxapi_auth = None - self.default_output = 'json' - self._connected = False + self._device_configs = {} + + self._module.params['url_username'] = self._module.params['username'] + self._module.params['url_password'] = self._module.params['password'] + + host = self._module.params['host'] + port = self._module.params['port'] + + if self._module.params['use_ssl']: + proto = 'https' + port = port or 443 + else: + proto = 'http' + port = port or 80 + + self._url = '%s://%s:%s/ins' % (proto, host, port) def _error(self, msg, **kwargs): self._nxapi_auth = None if 'url' not in kwargs: - kwargs['url'] = self.url - raise NetworkError(msg, **kwargs) + kwargs['url'] = self._url + self._module.fail_json(msg=msg, **kwargs) - def _get_body(self, commands, output, version='1.0', chunk='0', sid=None): + def _request_builder(self, commands, output, version='1.0', chunk='0', sid=None): """Encodes a NXAPI JSON request message """ try: @@ -120,64 +203,41 @@ class Nxapi(NxapiConfigMixin): return dict(ins_api=msg) - def connect(self, params, **kwargs): - host = params['host'] - port = params['port'] - - # sets the module_utils/urls.py req parameters - self.url_args.params['url_username'] = params['username'] - self.url_args.params['url_password'] = params['password'] - self.url_args.params['validate_certs'] = params['validate_certs'] - self.url_args.params['timeout'] = params['timeout'] - - if params['use_ssl']: - proto = 'https' - port = port or 443 - else: - proto = 'http' - port = port or 80 - - self.url = '%s://%s:%s/ins' % (proto, host, port) - self._connected = True - - def disconnect(self, **kwargs): - self.url = None - self._nxapi_auth = None - self._connected = False - - ### Command methods ### - - def execute(self, commands, output=None, **kwargs): - commands = collections.deque(commands) - output = output or self.default_output - - # only 10 commands can be encoded in each request + def send_request(self, commands, output='text'): + # only 10 show commands can be encoded in each request # messages sent to the remote device - stack = list() - requests = list() + if output != 'config': + commands = collections.deque(commands) + stack = list() + requests = list() - while commands: - stack.append(commands.popleft()) - if len(stack) == 10: - body = self._get_body(stack, output) - data = self._jsonify(body) + while commands: + stack.append(commands.popleft()) + if len(stack) == 10: + body = self._request_builder(stack, output) + data = self._module.jsonify(body) + requests.append(data) + stack = list() + + if stack: + body = self._request_builder(stack, output) + data = self._module.jsonify(body) requests.append(data) - stack = list() - if stack: - body = self._get_body(stack, output) - data = self._jsonify(body) - requests.append(data) + else: + requests = commands headers = {'Content-Type': 'application/json'} result = list() - timeout = self.url_args.params['timeout'] + timeout = self._module.params['timeout'] or 10 + for req in requests: if self._nxapi_auth: headers['Cookie'] = self._nxapi_auth response, headers = fetch_url( - self.url_args, self.url, data=data, headers=headers, timeout=timeout, method='POST' + self._module, self._url, data=data, headers=headers, + timeout=timeout, method='POST' ) self._nxapi_auth = headers.get('set-cookie') @@ -185,9 +245,9 @@ class Nxapi(NxapiConfigMixin): self._error(**headers) try: - response = json.loads(response.read()) + response = self._module.from_json(response.read()) except ValueError: - raise NetworkError(msg='unable to load response from device') + self._module.fail_json(msg='unable to parse response') output = response['ins_api']['outputs']['output'] for item in to_list(output): @@ -198,115 +258,96 @@ class Nxapi(NxapiConfigMixin): return result - def run_commands(self, commands, **kwargs): + + def get_config(self, flags=[]): + """Retrieves the current config from the device or cache + """ + cmd = 'show running-config ' + cmd += ' '.join(flags) + cmd = cmd.strip() + + try: + return self._device_configs[cmd] + except KeyError: + out = self.send_request(cmd) + cfg = str(out['result'][0]['output']).strip() + self._device_configs[cmd] = cfg + return cfg + + + def run_commands(self, commands, check_rc=True): + """Run list of commands on remote device and return results + """ output = None - cmds = list() + queue = list() responses = list() - for cmd in commands: - if output and output != cmd.output: - responses.extend(self.execute(cmds, output=output)) - cmds = list() + _send = lambda commands, output: self.send_request(commands, output) - output = cmd.output - cmds.append(str(cmd)) + for item in to_list(commands): + if is_json(item['command']): + item['command'] = str(item['command']).split('|')[0] + item['output'] = 'json' - if cmds: - responses.extend(self.execute(cmds, output=output)) + if all((output == 'json', item['output'] == 'text')) or all((output =='text', item['output'] == 'json')): + responses.extend(_send(queue, output)) + queue = list() + + output = item['output'] or 'json' + queue.append(item['command']) + + if queue: + responses.extend(_send(queue, output)) return responses - - ### Config methods ### - - def configure(self, commands): - commands = to_list(commands) - return self.execute(commands, output='config') - - def _jsonify(self, data): - for encoding in ("utf-8", "latin-1"): - try: - return json.dumps(data, encoding=encoding) - # Old systems using old simplejson module does not support encoding keyword. - except TypeError: - try: - new_data = json_dict_bytes_to_unicode(data, encoding=encoding) - except UnicodeDecodeError: - continue - return json.dumps(new_data) - except UnicodeDecodeError: - continue - self._error(msg='Invalid unicode encoding encountered') - -Nxapi = register_transport('nxapi')(Nxapi) + def load_config(self, config): + """Sends the ordered set of commands to the device + """ + cmds = ['configure terminal'] + cmds.extend(commands) + self.send_request(commands, output='config') -class Cli(NxapiConfigMixin, CliBase): +is_json = lambda x: str(x).endswith('| json') +is_text = lambda x: not is_json - CLI_PROMPTS_RE = [ - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'), - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$') - ] +def is_nxapi(module): + transport = module.params['transport'] + provider_transport = (module.params['provider'] or {}).get('transport') + return 'nxapi' in (transport, provider_transport) - CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"^% \w+", re.M), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), - re.compile(r"syntax error"), - re.compile(r"unknown command") - ] +def to_command(module, commands): + if is_nxapi(module): + default_output = 'json' + else: + default_output = 'text' - NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) + transform = ComplexList(dict( + command=dict(key=True), + output=dict(default=default_output), + prompt=dict(), + response=dict() + ), module) - def connect(self, params, **kwargs): - super(Cli, self).connect(params, kickstart=False, **kwargs) - self.shell.send('terminal length 0') + commands = transform(to_list(commands)) - ### Command methods ### + for index, item in enumerate(commands): + if is_json(item['command']): + item['output'] = 'json' + elif is_text(item['command']): + item['output'] = 'text' - def run_commands(self, commands): - cmds = list(prepare_commands(commands)) - responses = self.execute(cmds) - for index, cmd in enumerate(commands): - raw = cmd.args.get('raw') or False - if cmd.output == 'json' and not raw: - try: - responses[index] = json.loads(responses[index]) - except ValueError: - raise NetworkError( - msg='unable to load response from device', - response=responses[index], command=str(cmd) - ) - return responses +def get_config(module, flags=[]): + conn = get_connection(module) + return conn.get_config(flags) - ### Config methods ### +def run_commands(module, commands, check_rc=True): + conn = get_connection(module) + to_command(module, commands) + return conn.run_commands(commands) - def configure(self, commands, **kwargs): - commands = prepare_config(commands) - responses = self.execute(commands) - responses.pop(0) - return responses +def load_config(module, config): + conn = get_connection(module) + return conn.load_config(config) -Cli = register_transport('cli', default=True)(Cli) - - -def prepare_config(commands): - prepared = ['config'] - prepared.extend(to_list(commands)) - prepared.append('end') - return prepared - - -def prepare_commands(commands): - jsonify = lambda x: '%s | json' % x - for cmd in to_list(commands): - if cmd.output == 'json': - cmd.command_string = jsonify(cmd) - if cmd.command.endswith('| json'): - cmd.output = 'json' - yield cmd diff --git a/lib/ansible/module_utils/nxos_cli.py b/lib/ansible/module_utils/nxos_cli.py deleted file mode 100644 index 65623b6abe..0000000000 --- a/lib/ansible/module_utils/nxos_cli.py +++ /dev/null @@ -1,157 +0,0 @@ -# -# This code is part of Ansible, but is an independent component. -# -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# (c) 2017 Red Hat, Inc. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -import re - -from ansible.module_utils.shell import CliBase -from ansible.module_utils.basic import env_fallback, get_exception -from ansible.module_utils.network_common import to_list -from ansible.module_utils.netcli import Command -from ansible.module_utils.six import iteritems -from ansible.module_utils.network import NetworkError - -_DEVICE_CONFIGS = {} -_DEVICE_CONNECTION = None - -nxos_cli_argument_spec = { - 'host': dict(), - 'port': dict(type='int'), - - 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), - 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - - 'authorize': dict(default=False, fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'), - 'auth_pass': dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])), - - 'timeout': dict(type='int', default=10), - - 'provider': dict(type='dict'), - - # deprecated in Ansible 2.3 - 'transport': dict(), -} - -def check_args(module, warnings): - provider = module.params['provider'] or {} - for key in ('host', 'username', 'password'): - if not module.params[key] and not provider.get(key): - module.fail_json(msg='missing required argument %s' % key) - -class Cli(CliBase): - - CLI_PROMPTS_RE = [ - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'), - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$') - ] - - CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"^% \w+", re.M), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), - re.compile(r"syntax error"), - re.compile(r"unknown command") - ] - - NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) - - def __init__(self, module): - self._module = module - super(Cli, self).__init__() - - provider = self._module.params.get('provider') or dict() - for key, value in iteritems(provider): - if key in nxos_cli_argument_spec: - if self._module.params.get(key) is None and value is not None: - self._module.params[key] = value - - try: - self.connect() - except NetworkError: - exc = get_exception() - self._module.fail_json(msg=str(exc)) - - if module.params['authorize']: - self.authorize() - - def connect(self): - super(Cli, self).connect(self._module.params, kickstart=False) - self.shell.send('terminal length 0') - - -def connection(module): - global _DEVICE_CONNECTION - if not _DEVICE_CONNECTION: - cli = Cli(module) - _DEVICE_CONNECTION = cli - return _DEVICE_CONNECTION - - -def get_config(module, flags=[]): - cmd = 'show running-config ' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return _DEVICE_CONFIGS[cmd] - except KeyError: - conn = connection(module) - out = conn.exec_command(cmd) - cfg = str(out).strip() - _DEVICE_CONFIGS[cmd] = cfg - return cfg - -def run_commands(module, commands, check_rc=True): - responses = list() - conn = connection(module) - for cmd in to_list(commands): - rc, out, err = conn.exec_command(cmd) - if check_rc and rc != 0: - module.fail_json(msg=err, rc=rc) - responses.append(out) - return responses - -def load_config(module, commands): - conn = connection(module) - rc, out, err = conn.exec_command('configure') - if rc != 0: - module.fail_json(msg='unable to enter configuration mode', err=err) - - for command in to_list(commands): - if command == 'end': - continue - rc, out, err = module.exec_command(command) - if rc != 0: - module.fail_json(msg=err, command=command, rc=rc) - - conn.exec_command('end') diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server.py b/lib/ansible/modules/network/nxos/nxos_aaa_server.py index 51ed607a25..ef0c685b61 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages AAA server global configuration. description: - Manages AAA server global configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -155,220 +154,19 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.six import iteritems - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +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.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -490,9 +288,16 @@ def main(): choices=['enabled', 'disabled', 'default']), state=dict(choices=['default', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server_type = module.params['server_type'] global_key = module.params['global_key'] encrypt_type = module.params['encrypt_type'] @@ -555,7 +360,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_aaa_server_info(server_type, module) if 'configure' in cmds: cmds.pop(0) @@ -565,6 +370,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -572,3 +378,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py index 47a8b3f004..ee2732564b 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages AAA server host-specific configuration. description: - Manages AAA server host-specific configuration. -extends_documentation_fragment: nxos author: Jason Edelman (@jedelman8) notes: - Changes to the AAA server host key (shared secret) are not idempotent. @@ -150,236 +149,11 @@ changed: type: boolean sample: true ''' - - -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - if isinstance(response[0], str): - body = [json.loads(response[0])] - else: - body = response - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +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.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): @@ -387,11 +161,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -495,9 +268,16 @@ def main(): tacacs_port=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server_type = module.params['server_type'] address = module.params['address'] key = module.params['key'] @@ -565,7 +345,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_aaa_host_info(module, server_type, address) results = {} @@ -573,6 +353,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -580,3 +361,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_acl.py b/lib/ansible/modules/network/nxos/nxos_acl.py index cf2dc9a7fb..1ac359241c 100644 --- a/lib/ansible/modules/network/nxos/nxos_acl.py +++ b/lib/ansible/modules/network/nxos/nxos_acl.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages access list entries for ACLs. description: - Manages access list entries for ACLs. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -241,227 +240,21 @@ changed: type: boolean sample: true ''' - -import collections -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0]: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +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.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -621,24 +414,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( seq=dict(required=False, type='str'), @@ -685,9 +460,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] action = module.params['action'] remark = module.params['remark'] @@ -797,7 +579,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True new_existing_core, end_state, seqs = get_acl(module, name, seq) if 'configure' in cmds: @@ -806,6 +588,7 @@ def main(): results['proposed'] = proposed results['existing'] = existing_core results['changed'] = changed + results['warnings'] = warnings results['updates'] = cmds results['end_state'] = end_state @@ -814,3 +597,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_acl_interface.py b/lib/ansible/modules/network/nxos/nxos_acl_interface.py index f5219aa06d..7c74d2eaad 100644 --- a/lib/ansible/modules/network/nxos/nxos_acl_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_acl_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages applying ACLs to interfaces. description: - Manages applying ACLs to interfaces. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -99,216 +98,11 @@ changed: type: boolean sample: true ''' - -import collections -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0] or 'summary' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +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.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): @@ -316,11 +110,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'summary' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -446,24 +239,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( name=dict(required=False, type='str'), @@ -475,9 +250,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] name = module.params['name'] interface = module.params['interface'].lower() @@ -517,7 +299,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state_acls = get_acl_interface(module, name) interfaces_acls, this_dir_acl_intf = other_existing_acl( @@ -533,6 +315,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state results['acl_applied_to'] = end_state_acls @@ -541,3 +324,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp.py b/lib/ansible/modules/network/nxos/nxos_bgp.py index 8c4cc10d2a..62362ef8c1 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp.py @@ -30,7 +30,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP ASN configuration when C(vrf=default) or the whole VRF instance within the BGP process when @@ -361,156 +360,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] @@ -902,11 +756,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['timer_bgp_hold', 'timer_bgp_keepalive']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ "asn", @@ -1010,3 +871,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_af.py index 08f603f519..e804140084 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_af.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_af.py @@ -28,7 +28,6 @@ short_description: Manages BGP Address-family configuration. description: - Manages BGP Address-family configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP ASN configuration - Default, where supported, restores params default value. @@ -300,157 +299,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] BOOL_PARAMS = [ @@ -992,13 +845,20 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[DAMPENING_PARAMS, ['distance_ibgp', 'distance_ebgp', 'distance_local']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if module.params['dampening_routemap']: for param in DAMPENING_PARAMS: @@ -1108,3 +968,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py index 960e2d966f..7446559dab 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py @@ -28,7 +28,6 @@ short_description: Manages BGP neighbors configurations. description: - Manages BGP neighbors configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP neighbor configuration. - Default, where supported, restores params default value. @@ -245,156 +244,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] @@ -682,11 +536,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['timer_bgp_hold', 'timer_bgp_keepalive']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if module.params['pwd_type'] == 'default': module.params['pwd_type'] = '0' @@ -767,3 +628,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py index ebb886760a..f18a3f9daa 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py @@ -28,7 +28,6 @@ short_description: Manages BGP address-family's neighbors configuration. description: - Manages BGP address-family's neighbors configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP address-family's neighbor configuration. @@ -322,156 +321,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] BOOL_PARAMS = [ @@ -1004,11 +858,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['advertise_map_exist', 'advertise_map_non_exist']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if ((module.params['max_prefix_interval'] or module.params['max_prefix_warning'] or @@ -1120,3 +981,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_command.py b/lib/ansible/modules/network/nxos/nxos_command.py index b90034a09e..5daeb442fb 100644 --- a/lib/ansible/modules/network/nxos/nxos_command.py +++ b/lib/ansible/modules/network/nxos/nxos_command.py @@ -16,9 +16,11 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -31,7 +33,6 @@ description: read from the device. This module includes an argument that will cause the module to wait for a specific condition before returning or timing out if the condition is not met. -extends_documentation_fragment: nxos options: commands: description: @@ -152,37 +153,53 @@ failed_conditions: type: list sample: ['...', '...'] """ -import ansible.module_utils.nxos +import time -from ansible.module_utils.basic import get_exception -from ansible.module_utils.network import NetworkModule, NetworkError -from ansible.module_utils.netcli import CommandRunner -from ansible.module_utils.netcli import FailedConditionsError -from ansible.module_utils.netcli import FailedConditionalError -from ansible.module_utils.netcli import AddCommandError, AddConditionError - -VALID_KEYS = ['command', 'output', 'prompt', 'response'] +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.pycompat24 import get_exception +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import string_types +from ansible.module_utils.netcli import Conditional +from ansible.module_utils.network_common import ComplexList +from ansible.module_utils.nxos import nxos_argument_spec, check_args def to_lines(stdout): + lines = list() for item in stdout: if isinstance(item, basestring): item = str(item).split('\n') - yield item + lines.append(item) + return lines -def parse_commands(module): - for cmd in module.params['commands']: - if isinstance(cmd, basestring): - cmd = dict(command=cmd, output=None) - elif 'command' not in cmd: - module.fail_json(msg='command keyword argument is required') - elif cmd.get('output') not in [None, 'text', 'json']: - module.fail_json(msg='invalid output specified for command') - elif not set(cmd.keys()).issubset(VALID_KEYS): - module.fail_json(msg='unknown keyword specified') - yield cmd +def parse_commands(module, warnings): + transform = ComplexList(dict( + command=dict(key=True), + output=dict(), + prompt=dict(), + response=dict() + ), module) + + commands = transform(module.params['commands']) + + for index, item in enumerate(commands): + if module.check_mode and not item['command'].startswith('show'): + warnings.append( + 'Only show commands are supported when using check_mode, not ' + 'executing %s' % item['command'] + ) + + return commands + +def to_cli(obj): + cmd = obj['command'] + if obj.get('output') == 'json': + cmd += ' | json' + return cmd def main(): - spec = dict( + """entry point for module execution + """ + argument_spec = dict( # { command: , output: , prompt: , response: } commands=dict(type='list', required=True), @@ -193,66 +210,56 @@ def main(): interval=dict(default=1, type='int') ) - module = NetworkModule(argument_spec=spec, + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - commands = list(parse_commands(module)) - conditionals = module.params['wait_for'] or list() + + result = {'changed': False} warnings = list() - - runner = CommandRunner(module) - - for cmd in commands: - if module.check_mode and not cmd['command'].startswith('show'): - warnings.append('only show commands are supported when using ' - 'check mode, not executing `%s`' % cmd['command']) - else: - if cmd['command'].startswith('conf'): - module.fail_json(msg='nxos_command does not support running ' - 'config mode commands. Please use ' - 'nxos_config instead') - try: - runner.add_command(**cmd) - except AddCommandError: - exc = get_exception() - warnings.append('duplicate command detected: %s' % cmd) - - try: - for item in conditionals: - runner.add_conditional(item) - except AddConditionError: - exc = get_exception() - module.fail_json(msg=str(exc), condition=exc.condition) - - runner.retries = module.params['retries'] - runner.interval = module.params['interval'] - runner.match = module.params['match'] - - try: - runner.run() - except FailedConditionsError: - exc = get_exception() - module.fail_json(msg=str(exc), failed_conditions=exc.failed_conditions) - except FailedConditionalError: - exc = get_exception() - module.fail_json(msg=str(exc), failed_conditional=exc.failed_conditional) - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - result = dict(changed=False) - - result['stdout'] = list() - for cmd in commands: - try: - output = runner.get_command(cmd['command'], cmd.get('output')) - except ValueError: - output = 'command not executed due to check_mode, see warnings' - result['stdout'].append(output) - + check_args(module, warnings) + commands = parse_commands(module, warnings) result['warnings'] = warnings - result['stdout_lines'] = list(to_lines(result['stdout'])) + + wait_for = module.params['wait_for'] or list() + + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError: + exc = get_exception() + module.fail_json(msg=str(exc)) + + retries = module.params['retries'] + interval = module.params['interval'] + match = module.params['match'] + + while retries > 0: + responses = run_commands(module, commands) + + for item in list(conditionals): + if item(responses): + if match == 'any': + conditionals = list() + break + conditionals.remove(item) + + if not conditionals: + break + + time.sleep(interval) + retries -= 1 + + if conditionals: + failed_conditions = [item.raw for item in conditionals] + msg = 'One or more conditional statements have not be satisfied' + module.fail_json(msg=msg, failed_conditions=failed_conditions) + + result.update({ + 'stdout': responses, + 'stdout_lines': to_lines(responses) + }) module.exit_json(**result) diff --git a/lib/ansible/modules/network/nxos/nxos_config.py b/lib/ansible/modules/network/nxos/nxos_config.py index 2355ec37d8..fbb3ed7751 100644 --- a/lib/ansible/modules/network/nxos/nxos_config.py +++ b/lib/ansible/modules/network/nxos/nxos_config.py @@ -16,9 +16,11 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -32,7 +34,6 @@ description: an implementation for working with NXOS configuration sections in a deterministic way. This module works with either CLI or NXAPI transports. -extends_documentation_fragment: nxos options: lines: description: @@ -212,18 +213,28 @@ backup_path: type: path sample: /playbooks/ansible/backup/nxos_config.2016-07-16@22:28:34 """ - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.network import NetworkModule, NetworkError +from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.netcfg import NetworkConfig, dumps +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.nxos import check_args as nxos_check_args def check_args(module, warnings): + nxos_check_args(module, warnings) if module.params['force']: warnings.append('The force argument is deprecated, please use ' 'match=none instead. This argument will be ' 'removed in the future') +def get_running_config(module): + contents = module.params['config'] + if not contents: + flags = [] + if module.params['defaults']: + flags.append('all') + contents = get_config(module, flags=flags) + return NetworkConfig(indent=1, contents=contents) + def get_candidate(module): candidate = NetworkConfig(indent=2) if module.params['src']: @@ -233,13 +244,6 @@ def get_candidate(module): candidate.add(module.params['lines'], parents=parents) return candidate -def get_config(module): - contents = module.params['config'] - if not contents: - defaults = module.params['defaults'] - contents = module.config.get_config(include_defaults=defaults) - return NetworkConfig(indent=2, contents=contents) - def run(module, result): match = module.params['match'] replace = module.params['replace'] @@ -247,10 +251,9 @@ def run(module, result): candidate = get_candidate(module) if match != 'none': - config = get_config(module) + config = get_running_config(module) path = module.params['parents'] - configobjs = candidate.difference(config, path=path, match=match, - replace=replace) + configobjs = candidate.difference(config, match=match, replace=replace, path=path) else: configobjs = candidate.items @@ -264,22 +267,17 @@ def run(module, result): if module.params['after']: commands.extend(module.params['after']) - result['updates'] = commands + result['commands'] = commands + result['updates'] = commands if not module.check_mode: - module.config.load_config(commands) + load_config(module, commands) result['changed'] = True - if module.params['save']: - if not module.check_mode: - module.config.save_config() - result['changed'] = True - def main(): """ main entry point for module execution """ - argument_spec = dict( src=dict(type='path'), @@ -303,14 +301,15 @@ def main(): save=dict(type='bool', default=False), ) + argument_spec.update(nxos_argument_spec) + mutually_exclusive = [('lines', 'src')] required_if = [('match', 'strict', ['lines']), ('match', 'exact', ['lines']), ('replace', 'block', ['lines'])] - module = NetworkModule(argument_spec=argument_spec, - connect_on_load=False, + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, required_if=required_if, supports_check_mode=True) @@ -326,11 +325,13 @@ def main(): if module.params['backup']: result['__backup__'] = module.config.get_config() - try: + if any((module.params['src'], module.params['lines'])): run(module, result) - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) + + if module.params['save']: + if not module.check_mode: + run_commands(module, ['copy running-config startup-config']) + result['changed'] = True module.exit_json(**result) diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_global.py b/lib/ansible/modules/network/nxos/nxos_evpn_global.py index 20f6f8784e..befbb64c35 100644 --- a/lib/ansible/modules/network/nxos/nxos_evpn_global.py +++ b/lib/ansible/modules/network/nxos/nxos_evpn_global.py @@ -28,7 +28,6 @@ short_description: Handles the EVPN control plane for VXLAN. description: - Handles the EVPN control plane for VXLAN. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: nv_overlay_evpn: description: @@ -73,156 +72,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'nv_overlay_evpn': 'nv overlay evpn', @@ -286,9 +140,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + existing = invoke('get_existing', module) end_state = existing proposed = dict(nv_overlay_evpn=module.params['nv_overlay_evpn']) @@ -314,8 +175,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py index 08c73d6911..a62f28fd3c 100644 --- a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py +++ b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py @@ -29,7 +29,6 @@ description: - Manages Cisco Ethernet Virtual Private Network (EVPN) VXLAN Network Identifier (VNI) configurations of a Nexus device. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - default, where supported, restores params default value. - RD override is not permitted. You should set it to the default values @@ -127,156 +126,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'vni': 'vni', @@ -420,9 +274,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ 'vni', @@ -490,3 +351,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_facts.py b/lib/ansible/modules/network/nxos/nxos_facts.py index b3fd2a7fd9..4e1d4f1ebb 100644 --- a/lib/ansible/modules/network/nxos/nxos_facts.py +++ b/lib/ansible/modules/network/nxos/nxos_facts.py @@ -176,31 +176,24 @@ vlan_list: """ import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcli import CommandRunner, AddCommandError -from ansible.module_utils.network import NetworkModule, NetworkError +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network_common import exec_command from ansible.module_utils.six import iteritems -def add_command(runner, command, output=None): - try: - runner.add_command(command, output) - except AddCommandError: - # AddCommandError is raised for any issue adding a command to - # the runner. Silently ignore the exception in this case - pass - class FactsBase(object): - def __init__(self, module, runner): - self.module = module - self.runner = runner - self.facts = dict() - self.commands() + COMMANDS = frozenset() - def commands(self): - raise NotImplementedError + def __init__(self, module): + self.module = module + self.facts = dict() + self.responses = None + + def populate(self): + self.responses = run_commands(self.module, list(self.COMMANDS)) def transform_dict(self, data, keymap): transform = dict() @@ -224,33 +217,36 @@ class Default(FactsBase): ('host_name', 'hostname') ]) - def commands(self): - add_command(self.runner, 'show version', output='json') + COMMANDS = ['show version | json'] def populate(self): - data = self.runner.get_command('show version', output='json') + super(Default, self).populate() + data = self.responses[0] self.facts.update(self.transform_dict(data, self.VERSION_MAP)) class Config(FactsBase): - def commands(self): - add_command(self.runner, 'show running-config') + COMMANDS = ['show running-config'] def populate(self): - self.facts['config'] = self.runner.get_command('show running-config') + super(Config, self).populate() + data = self.responses[0] + self.facts['config'] = data class Hardware(FactsBase): - def commands(self): - add_command(self.runner, 'dir', output='text') - add_command(self.runner, 'show system resources', output='json') + COMMANDS = [ + 'dir', + 'show system resources | json' + ] def populate(self): - data = self.runner.get_command('dir', 'text') + super(Hardware, self).populate() + data = self.responses[0] self.facts['filesystems'] = self.parse_filesystems(data) - data = self.runner.get_command('show system resources', output='json') + data = self.responses[1] self.facts['memtotal_mb'] = int(data['memory_usage_total']) / 1024 self.facts['memfree_mb'] = int(data['memory_usage_free']) / 1024 @@ -282,38 +278,21 @@ class Interfaces(FactsBase): ('prefix', 'subnet') ]) - def commands(self): - add_command(self.runner, 'show interface', output='json') - - try: - self.module.cli('show ipv6 interface', 'json') - add_command(self.runner, 'show ipv6 interface', output='json') - self.ipv6 = True - except NetworkError: - self.ipv6 = False - - try: - self.module.cli(['show lldp neighbors']) - add_command(self.runner, 'show lldp neighbors', output='json') - self.lldp_enabled = True - except NetworkError: - self.lldp_enabled = False - def populate(self): self.facts['all_ipv4_addresses'] = list() self.facts['all_ipv6_addresses'] = list() - data = self.runner.get_command('show interface', 'json') + data = run_commands(self.module, ['show interface | json'])[0] self.facts['interfaces'] = self.populate_interfaces(data) - if self.ipv6: - data = self.runner.get_command('show ipv6 interface', 'json') - if data: - self.parse_ipv6_interfaces(data) + rc, out, err = exec_command(self.module, 'show ipv6 interface | json') + if rc == 0: + if out: + self.parse_ipv6_interfaces(out) - if self.lldp_enabled: - data = self.runner.get_command('show lldp neighbors', 'json') - self.facts['neighbors'] = self.populate_neighbors(data) + rc, out, err = exec_command(self.module, 'show lldp neighbors') + if rc == 0: + self.facts['neighbors'] = self.populate_neighbors(out) def populate_interfaces(self, data): interfaces = dict() @@ -390,27 +369,30 @@ class Legacy(FactsBase): ('total_capa', 'total_capacity') ]) - def commands(self): - add_command(self.runner, 'show version', output='json') - add_command(self.runner, 'show module', output='json') - add_command(self.runner, 'show environment', output='json') - add_command(self.runner, 'show interface', output='json') - add_command(self.runner, 'show vlan brief', output='json') + COMMANDS = [ + 'show version | json', + 'show module | json', + 'show environment | json', + 'show interface | json', + 'show vlan brief | json' + ] + def populate(self): - data = self.runner.get_command('show version', 'json') + super(Legacy, self).populate() + data = self.responses[0] self.facts.update(self.transform_dict(data, self.VERSION_MAP)) - data = self.runner.get_command('show interface', 'json') + data = self.responses[3] self.facts['_interfaces_list'] = self.parse_interfaces(data) - data = self.runner.get_command('show vlan brief', 'json') + data = self.responses[4] self.facts['_vlan_list'] = self.parse_vlans(data) - data = self.runner.get_command('show module', 'json') + data = self.responses[1] self.facts['_module'] = self.parse_module(data) - data = self.runner.get_command('show environment', 'json') + data = self.responses[2] self.facts['_fan_info'] = self.parse_fan_info(data) self.facts['_power_supply_info'] = self.parse_power_supply_info(data) @@ -463,7 +445,12 @@ def main(): gather_subset=dict(default=['!config'], type='list') ) - module = NetworkModule(argument_spec=spec, supports_check_mode=True) + spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=spec, supports_check_mode=True) + + warnings = list() + check_args(module, warnings) gather_subset = module.params['gather_subset'] @@ -501,25 +488,13 @@ def main(): facts = dict() facts['gather_subset'] = list(runable_subsets) - runner = CommandRunner(module) - instances = list() for key in runable_subsets: - instances.append(FACT_SUBSETS[key](module, runner)) + instances.append(FACT_SUBSETS[key](module)) - try: - runner.run() - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - try: - for inst in instances: - inst.populate() - facts.update(inst.facts) - except Exception: - raise - module.exit_json(out=module.from_json(runner.items)) + for inst in instances: + inst.populate() + facts.update(inst.facts) ansible_facts = dict() for key, value in iteritems(facts): @@ -530,7 +505,7 @@ def main(): key = 'ansible_net_%s' % key ansible_facts[key] = value - module.exit_json(ansible_facts=ansible_facts) + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/nxos/nxos_feature.py b/lib/ansible/modules/network/nxos/nxos_feature.py index 3e23d22d08..336ee7085d 100644 --- a/lib/ansible/modules/network/nxos/nxos_feature.py +++ b/lib/ansible/modules/network/nxos/nxos_feature.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manage features in NX-OS switches. description: - Offers ability to enable and disable features in NX-OS. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,244 +96,11 @@ feature: type: string sample: "vpc" ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'xml' in response[0]: - body = [] - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - command += ' | json' - cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) - elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - - return body - +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.basic import AnsibleModule def apply_key_map(key_map, table): new_dict = {} @@ -354,7 +120,8 @@ def get_available_features(feature, module): feature_regex = '(?P\S+)\s+\d+\s+(?P.*)' command = 'show feature' - body = execute_show_command(command, module, command_type='cli_show_ascii') + command = {'command': command, 'output': 'text'} + body = run_commands(module, [command]) split_body = body[0].splitlines() for line in split_body: @@ -451,9 +218,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + feature = validate_feature(module) state = module.params['state'].lower() @@ -477,7 +251,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True updated_features = get_available_features(feature, module) existstate = updated_features[feature] @@ -491,6 +265,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['feature'] = module.params['feature'] module.exit_json(**results) @@ -498,3 +273,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_file_copy.py b/lib/ansible/modules/network/nxos/nxos_file_copy.py index 8f241658f0..891f32e123 100644 --- a/lib/ansible/modules/network/nxos/nxos_file_copy.py +++ b/lib/ansible/modules/network/nxos/nxos_file_copy.py @@ -31,7 +31,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - The feature must be enabled with feature scp-server. - If the file is already present (md5 sums match), no transfer will @@ -82,205 +81,29 @@ remote_file: type: string sample: '/path/to/remote/file' ''' - - import os -from scp import SCPClient -import paramiko +import re import time -# COMMON CODE FOR MIGRATION -import re +import paramiko -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule try: - from ansible.module_utils.nxos import get_module + from scp import SCPClient + HAS_SCP = True except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - + HAS_SCP = False def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': cmds = [command] - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -372,8 +195,20 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + if not HAS_SCP: + module.fail_json( + msg='library scp is required but does not appear to be ' + 'installed. It can be installed using `pip install scp`' + ) + + warnings = list() + check_args(module, warnings) local_file = module.params['local_file'] remote_file = module.params['remote_file'] @@ -409,8 +244,10 @@ def main(): transfer_status=transfer_status, local_file=local_file, remote_file=remote_file, + warnings=warnings, file_system=file_system) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_gir.py b/lib/ansible/modules/network/nxos/nxos_gir.py index cb22ae12d4..5d091a70e5 100644 --- a/lib/ansible/modules/network/nxos/nxos_gir.py +++ b/lib/ansible/modules/network/nxos/nxos_gir.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Trigger a graceful removal or insertion (GIR) of the switch. description: - Trigger a graceful removal or insertion (GIR) of the switch. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -161,220 +160,22 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_system_mode(module): command = 'show system mode' body = execute_show_command(command, module)[0] @@ -468,7 +269,10 @@ def main(): state=dict(choices=['absent', 'present', 'default'], default='present', required=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[[ 'system_mode_maintenance', 'system_mode_maintenance_dont_generate_profile', @@ -485,6 +289,10 @@ def main(): ]], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] mode = get_system_mode(module) commands = get_commands(module, state, mode) @@ -493,7 +301,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True result = {} @@ -504,8 +312,11 @@ def main(): result['final_system_mode'] = final_system_mode result['updates'] = commands + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py b/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py index 5d7751141b..fa5328f9ce 100644 --- a/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py +++ b/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py @@ -29,7 +29,6 @@ description: - Manage a maintenance-mode or normal-mode profile with configuration commands that can be applied during graceful removal or graceful insertion. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -117,159 +116,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def get_existing(module): @@ -315,24 +166,6 @@ def invoke(name, *args, **kwargs): return func(*args, **kwargs) -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( commands=dict(required=False, type='list'), @@ -342,9 +175,16 @@ def main(): include_defaults=dict(default=False), config=dict() ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] commands = module.params['commands'] or [] @@ -363,7 +203,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = invoke('get_existing', module) @@ -376,8 +216,11 @@ def main(): result['proposed'] = commands result['updates'] = cmds + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_hsrp.py b/lib/ansible/modules/network/nxos/nxos_hsrp.py index c5f766ca7a..5854be331c 100644 --- a/lib/ansible/modules/network/nxos/nxos_hsrp.py +++ b/lib/ansible/modules/network/nxos/nxos_hsrp.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages HSRP configuration on NX-OS switches. description: - Manages HSRP configuration on NX-OS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -143,239 +142,21 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -619,9 +400,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'].lower() group = module.params['group'] version = module.params['version'] @@ -699,7 +487,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - body = execute_config_command(commands, module) + load_config(module, commands) if transport == 'cli': validate_config(body, vip, module) changed = True @@ -713,9 +501,11 @@ def main(): results['end_state'] = end_state results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp.py b/lib/ansible/modules/network/nxos/nxos_igmp.py index 7cc36bb392..1262a649e3 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages IGMP global configuration. description: - Manages IGMP global configuration configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -110,159 +109,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'flush_routes': 'ip igmp flush-routes', @@ -343,9 +194,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] restart = module.params['restart'] @@ -392,8 +250,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py index 1432c4d47f..65c3eacf27 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages IGMP interface configuration. description: - Manages IGMP interface configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -233,225 +232,21 @@ changed: sample: true ''' -import json -import collections +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -712,24 +507,6 @@ def config_remove_oif(existing, existing_oif_prefix_source): return commands -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( interface=dict(required=True, type='str'), @@ -755,9 +532,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'] oif_prefix = module.params['oif_prefix'] @@ -891,7 +675,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = get_igmp_interface(module, interface) if 'configure' in cmds: @@ -901,6 +685,7 @@ def main(): results['existing'] = existing_copy results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -908,3 +693,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py b/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py index f63b75f0ed..065369a50b 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py @@ -30,7 +30,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - When C(state=default), params will be reset to a default state. - C(group_timeout) also accepts I(never) as an input. @@ -129,229 +128,23 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - if isinstance(response[0], str): - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response[0])] - else: - body = response - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -366,24 +159,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_group_timeout(config): command = 'ip igmp snooping group-timeout' REGEX = re.compile(r'(?:{0}\s)(?P.*)$'.format(command), re.M) @@ -492,9 +267,16 @@ def main(): v3_report_supp=dict(required=False, type='bool'), state=dict(choices=['present', 'default'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + snooping = module.params['snooping'] link_local_grp_supp = module.params['link_local_grp_supp'] report_supp = module.params['report_supp'] @@ -539,7 +321,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_igmp_snooping(module) if 'configure' in cmds: cmds.pop(0) @@ -548,9 +330,11 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_install_os.py b/lib/ansible/modules/network/nxos/nxos_install_os.py index f0ba09be7c..59640dc8df 100644 --- a/lib/ansible/modules/network/nxos/nxos_install_os.py +++ b/lib/ansible/modules/network/nxos/nxos_install_os.py @@ -115,220 +115,23 @@ install_state: ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_boot_options(module): """Get current boot variables like system image and kickstart image. @@ -376,7 +179,7 @@ def set_boot_options(module, image_name, kickstart=None): else: commands.append( 'install all system %s kickstart %s' % (image_name, kickstart)) - execute_config_command(commands, module) + load_config(module, commands) def main(): @@ -384,9 +187,16 @@ def main(): system_image_file=dict(required=True), kickstart_image_file=dict(required=False), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + system_image_file = module.params['system_image_file'] kickstart_image_file = module.params['kickstart_image_file'] @@ -413,8 +223,9 @@ def main(): else: install_state = current_boot_options - module.exit_json(changed=changed, install_state=install_state) + module.exit_json(changed=changed, install_state=install_state, warnings=warnings) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_interface.py b/lib/ansible/modules/network/nxos/nxos_interface.py index fafbae89ea..93532df3fc 100644 --- a/lib/ansible/modules/network/nxos/nxos_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_interface.py @@ -162,157 +162,12 @@ changed: sample: true ''' -import json - -# COMMON CODE FOR MIGRATION - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE def is_default_interface(interface, module): @@ -710,95 +565,23 @@ def smart_existing(module, intf_type, normalized_interface): return existing, is_default -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + cmds = [{'command': command, 'output': 'json'}] + body = run_commands(module, cmds) return body def execute_modified_show_for_cli_text(command, module): cmds = [command] if module.params['transport'] == 'cli': - response = execute_show(cmds, module) + body = run_commands(module, cmds) else: - response = execute_show(cmds, module, command_type='cli_show_ascii') + body = run_commands(module, cmds) body = response return body @@ -840,10 +623,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['interface', 'interface_type']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + interface = module.params['interface'] interface_type = module.params['interface_type'] admin_state = module.params['admin_state'] @@ -937,7 +726,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True if module.params['interface']: if delta.get('mode'): # or delta.get('admin_state'): @@ -948,7 +737,7 @@ def main(): c1 = 'interface {0}'.format(normalized_interface) c2 = get_admin_state(delta, normalized_interface, admin_state) cmds2 = [c1, c2] - execute_config_command(cmds2, module) + load_config(module, cmds2) cmds.extend(cmds2) end_state, is_default = smart_existing(module, intf_type, normalized_interface) @@ -962,9 +751,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py index 36fbf5cd28..61f22b5363 100644 --- a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py +++ b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py @@ -28,7 +28,6 @@ short_description: Manages configuration of an OSPF interface instance. description: - Manages configuration of an OSPF interface instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default, where supported, restores params default value. - To remove an existing authentication configuration you should use @@ -167,156 +166,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = [ 'passive_interface', @@ -597,7 +451,10 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['message_digest_key_id', 'message_digest_algorithm_type', 'message_digest_encryption_type', @@ -607,6 +464,9 @@ def main(): if not module.params['interface'].startswith('loopback'): module.params['interface'] = module.params['interface'].capitalize() + warnings = list() + check_args(module, warnings) + for param in ['message_digest_encryption_type', 'message_digest_algorithm_type', 'message_digest_password']: @@ -674,8 +534,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed_args + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ip_interface.py b/lib/ansible/modules/network/nxos/nxos_ip_interface.py index e2ae39955c..e36a51aed2 100644 --- a/lib/ansible/modules/network/nxos/nxos_ip_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_ip_interface.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages L3 attributes for IPv4 and IPv6 interfaces. description: - Manages Layer 3 attributes for IPv4 and IPv6 interfaces. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -111,242 +110,21 @@ changed: sample: true ''' -import json -import collections +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0] or 'show run' in response[0] or response[0] == '\n': - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -640,9 +418,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + addr = module.params['addr'] version = module.params['version'] mask = module.params['mask'] @@ -702,7 +487,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state, address_list = get_ip_interface(interface, version, module) @@ -715,9 +500,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_mtu.py b/lib/ansible/modules/network/nxos/nxos_mtu.py index 35b3303c36..2299e79134 100644 --- a/lib/ansible/modules/network/nxos/nxos_mtu.py +++ b/lib/ansible/modules/network/nxos/nxos_mtu.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages MTU settings on Nexus switch. description: - Manages MTU settings on Nexus switch. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -118,245 +117,19 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +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.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -503,9 +276,15 @@ def main(): sysmtu=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, - required_together=[['mtu', 'interface']], - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + required_together=[['mtu', 'interface']], + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) interface = module.params['interface'] mtu = module.params['mtu'] @@ -576,7 +355,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) if interface: end_state = get_mtu(interface, module) else: @@ -590,9 +369,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp.py b/lib/ansible/modules/network/nxos/nxos_ntp.py index 721fc473f7..27285bf691 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages core NTP configuration. description: - Manages core NTP configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) options: @@ -125,243 +124,23 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -530,12 +309,19 @@ def main(): source_int=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[ ['server','peer'], ['source_addr','source_int']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server = module.params['server'] or None peer = module.params['peer'] or None key_id = module.params['key_id'] @@ -616,7 +402,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_ntp_existing(address, peer_type, module)[0] if 'configure' in cmds: cmds.pop(0) @@ -626,6 +412,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state results['peer_server_list'] = peer_server_list @@ -635,3 +422,4 @@ def main(): from ansible.module_utils.basic import * if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp_auth.py b/lib/ansible/modules/network/nxos/nxos_ntp_auth.py index 4d094c49cd..43811c12d8 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp_auth.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp_auth.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages NTP authentication. description: - Manages NTP authentication. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -123,243 +122,23 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -503,9 +282,16 @@ def main(): authentication=dict(choices=['on', 'off']), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + key_id = module.params['key_id'] md5string = module.params['md5string'] auth_type = module.params['auth_type'] @@ -548,7 +334,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: try: - execute_config_command(cmds, module) + load_config(module, cmds) except ShellError: clie = get_exception() module.fail_json(msg=str(clie) + ": " + cmds) @@ -564,9 +350,11 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp_options.py b/lib/ansible/modules/network/nxos/nxos_ntp_options.py index 0bf1fb70f7..23be4f8c73 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp_options.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp_options.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages NTP options. description: - Manages NTP options, e.g. authoritative server and logging. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -104,243 +103,24 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -442,10 +222,17 @@ def main(): logging=dict(required=False, type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['master', 'logging']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + master = module.params['master'] stratum = module.params['stratum'] logging = module.params['logging'] @@ -500,7 +287,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_ntp_options(module) if 'configure' in cmds: cmds.pop(0) @@ -510,6 +297,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -517,3 +305,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_nxapi.py b/lib/ansible/modules/network/nxos/nxos_nxapi.py index 9a3985a92f..5108b24d52 100644 --- a/lib/ansible/modules/network/nxos/nxos_nxapi.py +++ b/lib/ansible/modules/network/nxos/nxos_nxapi.py @@ -16,10 +16,11 @@ # along with Ansible. If not, see . # - -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -32,7 +33,6 @@ description: NXAPI feature is absent from the configuration by default. Since this module manages the NXAPI feature it only supports the use of the C(Cli) transport. -extends_documentation_fragment: nxos options: http_port: description: @@ -84,15 +84,6 @@ options: default: no choices: ['yes', 'no'] aliases: ['enable_sandbox'] - config: - description: - - The C(config) argument provides an optional argument to - specify the device running-config to used as the basis for - configuring the remote system. The C(config) argument accepts - a string value that represents the device configuration. - required: false - default: null - version_added: "2.2" state: description: - The C(state) argument controls whether or not the NXAPI @@ -106,17 +97,9 @@ options: """ EXAMPLES = """ -# Note: examples below use the following provider dict to handle -# transport and authentication to the node. -vars: - cli: - host: "{{ inventory_hostname }}" - username: admin - password: admin - - name: Enable NXAPI access with default configuration nxos_nxapi: - provider: "{{ cli }}" + state: present - name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled nxos_nxapi: @@ -124,12 +107,10 @@ vars: https_port: 9443 https: yes enable_sandbox: no - provider: "{{ cli }}" - name: remove NXAPI configuration nxos_nxapi: state: absent - provider: "{{ cli }}" """ RETURN = """ @@ -142,189 +123,172 @@ updates: sample: ['no feature nxapi'] """ import re -import time -from ansible.module_utils.netcfg import NetworkConfig, dumps -from ansible.module_utils.nxos import NetworkModule, NetworkError -from ansible.module_utils.basic import get_exception +from functools import partial -PRIVATE_KEYS_RE = re.compile('__.+__') +from ansible.module_utils.nxos import run_commands, load_config +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.nxos import check_args as nxos_check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import NetworkConfig +from ansible.module_utils.six import iteritems -def invoke(name, *args, **kwargs): - func = globals().get(name) - if func: - return func(*args, **kwargs) +def check_args(module, warnings): + nxos_check_args(module, warnings) -def get_instance(module): - instance = dict(state='absent') - try: - resp = module.cli('show nxapi', 'json') - except NetworkError: - return instance + state = module.params['state'] - instance['state'] = 'present' + if state == 'started': + module.params['state'] = 'present' + warnings.append('state=started is deprecated and will be removed in a ' + 'a future release. Please use state=present instead') + elif state == 'stopped': + module.params['state'] = 'absent' + warnings.append('state=stopped is deprecated and will be removed in a ' + 'a future release. Please use state=absent instead') - instance['http'] = 'http_port' in resp[0] - instance['http_port'] = resp[0].get('http_port') or 80 + if module.params['transport'] == 'nxapi': + module.fail_json(msg='module not supported over nxapi transport') - instance['https'] = 'https_port' in resp[0] - instance['https_port'] = resp[0].get('https_port') or 443 + for key in ['config']: + if module.params[key]: + warnings.append('argument %s is deprecated and will be ignored' % key) - instance['sandbox'] = resp[0]['sandbox_status'] + return warnings - return instance +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates -def present(module, instance, commands): - commands.append('feature nxapi') - setters = set() - for key, value in module.argument_spec.items(): - setter = value.get('setter') or 'set_%s' % key - if setter not in setters: - setters.add(setter) - if module.params[key] is not None: - invoke(setter, module, instance, commands) + needs_update = lambda x: want.get(x) is not None and (want.get(x) != have.get(x)) -def absent(module, instance, commands): - if instance['state'] != 'absent': - commands.append('no feature nxapi') + if needs_update('state'): + if want['state'] == 'absent': + return ['no feature nxapi'] + commands.append('feature nxapi') -def set_http(module, instance, commands): - port = module.params['http_port'] - if not 0 <= port <= 65535: + if any((needs_update('http'), needs_update('http_port'))): + if want['http'] is True or (want['http'] is None and have['http'] is True): + port = want['http_port'] or 80 + commands.append('nxapi http port %s' % port) + elif want['http'] is False: + commands.append('no nxapi http') + + if any((needs_update('https'), needs_update('https_port'))): + if want['https'] is True or (want['https'] is None and have['https'] is True): + port = want['https_port'] or 443 + commands.append('nxapi https port %s' % port) + elif want['https'] is False: + commands.append('no nxapi https') + + if needs_update('sandbox'): + cmd = 'nxapi sandbox' + if not want['sandbox']: + cmd = 'no %s' % cmd + commands.append(cmd) + + return commands + +def parse_http(data): + match = re.search('HTTP Port:\s+(\d+)', data, re.M) + if match: + return {'http': True, 'http_port': match.group(1)} + else: + return {'http': False, 'http_port': None} + +def parse_https(data): + match = re.search('HTTPS Port:\s+(\d+)', data, re.M) + if match: + return {'https': True, 'https_port': match.group(1)} + else: + return {'https': False, 'https_port': None} + +def parse_sandbox(data): + match = re.search('Sandbox:\s+(.+)$', data, re.M) + return {'sandbox': match.group(1) == 'Enabled'} + +def map_config_to_obj(module): + out = run_commands(module, ['show nxapi'], check_rc=False) + if not out[0]: + return {'state': 'absent'} + + out = str(out[0]).strip() + + obj = {'state': 'present'} + obj.update(parse_http(out)) + obj.update(parse_https(out)) + obj.update(parse_sandbox(out)) + + return obj + +def validate_http_port(value, module): + if not 1 <= module.params['http_port'] <= 65535: module.fail_json(msg='http_port must be between 1 and 65535') - elif module.params['http'] is True: - commands.append('nxapi http port %s' % port) - elif module.params['http'] is False: - commands.append('no nxapi http') -def set_https(module, instance, commands): - port = module.params['https_port'] - if not 0 <= port <= 65535: +def validate_https_port(value, module): + if not 1 <= module.params['https_port'] <= 65535: module.fail_json(msg='https_port must be between 1 and 65535') - elif module.params['https'] is True: - commands.append('nxapi https port %s' % port) - elif module.params['https'] is False: - commands.append('no nxapi https') -def set_sandbox(module, instance, commands): - if module.params['sandbox'] is True: - commands.append('nxapi sandbox') - elif module.params['sandbox'] is False: - commands.append('no nxapi sandbox') +def map_params_to_obj(module): + obj = { + 'http': module.params['http'], + 'http_port': module.params['http_port'], + 'https': module.params['https'], + 'https_port': module.params['https_port'], + 'sandbox': module.params['sandbox'], + 'state': module.params['state'] + } -def get_config(module): - contents = module.params['config'] - if not contents: - try: - contents = module.cli(['show running-config nxapi all'])[0] - except NetworkError: - contents = None - config = NetworkConfig(indent=2) - if contents: - config.load(contents) - return config - -def load_checkpoint(module, result): - try: - checkpoint = result['__checkpoint__'] - module.cli(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint], output='text') - except KeyError: - module.fail_json(msg='unable to rollback, checkpoint not found') - except NetworkError: - exc = get_exception() - msg = 'unable to rollback configuration' - module.fail_json(msg=msg, checkpoint=checkpoint, **exc.kwargs) - -def load_config(module, commands, result): - # create a config checkpoint - checkpoint = 'ansible_%s' % int(time.time()) - module.cli(['checkpoint %s' % checkpoint], output='text') - result['__checkpoint__'] = checkpoint - - # load the config into the device - module.config.load_config(commands) - - # load was successfully, remove the config checkpoint - module.cli(['no checkpoint %s' % checkpoint]) - -def load(module, commands, result): - candidate = NetworkConfig(indent=2, contents='\n'.join(commands)) - config = get_config(module) - configobjs = candidate.difference(config) - - if configobjs: - commands = dumps(configobjs, 'commands').split('\n') - result['updates'] = commands - if not module.check_mode: - load_config(module, commands, result) - result['changed'] = True - -def clean_result(result): - # strip out any keys that have two leading and two trailing - # underscore characters - for key in result.keys(): - if PRIVATE_KEYS_RE.match(key): - del result[key] + for key, value in iteritems(obj): + if value: + validator = globals().get('validate_%s' % key) + if validator: + validator(value, module) + return obj def main(): """ main entry point for module execution """ - argument_spec = dict( - http=dict(aliases=['enable_http'], default=True, type='bool', setter='set_http'), - http_port=dict(default=80, type='int', setter='set_http'), + http=dict(aliases=['enable_http'], type='bool'), + http_port=dict(type='int'), - https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'), - https_port=dict(default=443, type='int', setter='set_https'), + https=dict(aliases=['enable_https'], type='bool'), + https_port=dict(type='int'), - sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'), - - # Only allow configuration of NXAPI using cli transport - transport=dict(required=True, choices=['cli']), + sandbox=dict(aliases=['enable_sandbox'], type='bool'), + # deprecated (Ansible 2.3) arguments config=dict(), - # Support for started and stopped is for backwards capability only and - # will be removed in a future version state=dict(default='present', choices=['started', 'stopped', 'present', 'absent']) ) - module = NetworkModule(argument_spec=argument_spec, - connect_on_load=False, + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - state = module.params['state'] + + result = {'changed': False} warnings = list() + check_args(module, warnings) + result['warnings'] = warnings - result = dict(changed=False, warnings=warnings) + want = map_params_to_obj(module) + have = map_config_to_obj(module) - if state == 'started': - state = 'present' - warnings.append('state=started is deprecated and will be removed in a ' - 'a future release. Please use state=present instead') - elif state == 'stopped': - state = 'absent' - warnings.append('state=stopped is deprecated and will be removed in a ' - 'a future release. Please use state=absent instead') + commands = map_obj_to_commands((want, have), module) + result['commands'] = commands - commands = list() - instance = get_instance(module) + if commands: + if not module.check_mode: + load_config(module, commands) + result['changed'] = True - invoke(state, module, instance, commands) - - try: - load(module, commands, result) - except (ValueError, NetworkError): - load_checkpoint(module, result) - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - clean_result(result) module.exit_json(**result) - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/network/nxos/nxos_ospf.py b/lib/ansible/modules/network/nxos/nxos_ospf.py index ead87ee71d..a0a98ae942 100644 --- a/lib/ansible/modules/network/nxos/nxos_ospf.py +++ b/lib/ansible/modules/network/nxos/nxos_ospf.py @@ -28,7 +28,6 @@ short_description: Manages configuration of an ospf instance. description: - Manages configuration of an ospf instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: ospf: description: @@ -81,156 +80,13 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { 'ospf': 'router ospf' @@ -304,9 +160,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] ospf = str(module.params['ospf']) @@ -345,3 +208,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py index 81d77e1c13..c0edc9a42d 100644 --- a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py +++ b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py @@ -28,7 +28,6 @@ short_description: Manages a VRF for an OSPF router. description: - Manages a VRF for an OSPF router. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Value I(default) restores params default value, if any. Otherwise it removes the existing param configuration. @@ -172,156 +171,13 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { @@ -527,9 +383,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ 'vrf', @@ -591,3 +454,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_overlay_global.py b/lib/ansible/modules/network/nxos/nxos_overlay_global.py index 5d31b049a8..01ba9d9278 100644 --- a/lib/ansible/modules/network/nxos/nxos_overlay_global.py +++ b/lib/ansible/modules/network/nxos/nxos_overlay_global.py @@ -28,7 +28,6 @@ short_description: Configures anycast gateway MAC of the switch. description: - Configures anycast gateway MAC of the switch. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default restores params default value - Supported MAC address format are "E.E.E", "EE-EE-EE-EE-EE-EE", @@ -109,159 +108,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'anycast_gateway_mac': 'fabric forwarding anycast-gateway-mac', @@ -372,12 +223,15 @@ def main(): argument_spec = dict( anycast_gateway_mac=dict(required=True, type='str'), m_facts=dict(required=False, default=False, type='bool'), - include_defaults=dict(default=True), - config=dict(), - save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) args = [ 'anycast_gateway_mac' @@ -392,22 +246,20 @@ def main(): candidate = CustomNetworkConfig(indent=3) invoke('get_commands', module, existing, proposed, candidate) - try: - response = load_config(module, candidate) - result.update(response) - except ShellError: - exc = get_exception() - module.fail_json(msg=str(exc)) + if not module.check_mode: + load_config(module, candidate) - result['connected'] = module.connected if module._verbosity > 0: end_state = invoke('get_existing', module, args) result['end_state'] = end_state result['existing'] = existing result['proposed'] = proposed + result['warnings'] = True + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim.py b/lib/ansible/modules/network/nxos/nxos_pim.py index 74e679bbaf..d3f13913d3 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim.py +++ b/lib/ansible/modules/network/nxos/nxos_pim.py @@ -28,7 +28,6 @@ short_description: Manages configuration of a PIM instance. description: - Manages configuration of a Protocol Independent Multicast (PIM) instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: ssm_range: description: @@ -73,159 +72,13 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { @@ -291,9 +144,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + splitted_ssm_range = module.params['ssm_range'].split('.') if len(splitted_ssm_range) != 4 and module.params['ssm_range'] != 'none': module.fail_json(msg="Valid ssm_range values are multicast addresses " @@ -334,3 +194,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim_interface.py b/lib/ansible/modules/network/nxos/nxos_pim_interface.py index ba90299a9e..4db51f94be 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_pim_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages PIM interface configuration. description: - Manages PIM interface configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -187,232 +186,15 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + import time -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module, text=False): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n' or '^' in response[0]: - body = [] - elif 'show run' in command or text: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show', text=False): @@ -420,11 +202,10 @@ def execute_show_command(command, module, command_type='cli_show', text=False): if 'show run' not in command and text is False: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module, text=text) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -814,9 +595,16 @@ def main(): state=dict(choices=['present', 'absent', 'default'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] sparse = module.params['sparse'] @@ -912,7 +700,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) time.sleep(1) get_existing = get_pim_interface(module, interface) end_state, jp_bidir, isauth = local_existing(get_existing) @@ -923,6 +711,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -930,3 +719,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py index f32bee8dfb..3a6287bb00 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py +++ b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py @@ -29,7 +29,6 @@ description: - Manages configuration of an Protocol Independent Multicast (PIM) static rendezvous point (RP) address instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) remove the whole rp-address configuration, if existing. options: @@ -103,159 +102,13 @@ changed: -# COMMON CODE FOR MIGRATION import re +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re BOOL_PARAMS = ['bidir'] PARAM_TO_COMMAND_KEYMAP = { @@ -357,12 +210,19 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['group_list', 'route_map'], ['group_list', 'prefix_list'], ['route_map', 'prefix_list']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ @@ -414,3 +274,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ping.py b/lib/ansible/modules/network/nxos/nxos_ping.py index 3a9b628f94..a3a7cc7419 100644 --- a/lib/ansible/modules/network/nxos/nxos_ping.py +++ b/lib/ansible/modules/network/nxos/nxos_ping.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Tests reachability using ping from Nexus switch. description: - Tests reachability using ping from switch to a remote destination. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -115,163 +114,9 @@ packet_loss: type: string sample: "0.00%" ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 get_summary(results_list, reference_point): summary_string = results_list[reference_point+1] @@ -313,48 +158,9 @@ def get_statistics_summary_line(response_as_list): return index -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command_ping(command, module, command_type='cli_show_ascii'): - cmds = [command] - if module.params['transport'] == 'cli': - body = execute_show(cmds, module) - elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) - return body - - def get_ping_results(command, module, transport): - ping = execute_show_command_ping(command, module)[0] + cmd = {'command': command, 'output': 'text'} + ping = run_commands(module, [cmd])[0] if not ping: module.fail_json(msg="An unexpected error occurred. Check all params.", @@ -388,9 +194,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + destination = module.params['dest'] count = module.params['count'] vrf = module.params['vrf'] @@ -444,3 +257,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_portchannel.py b/lib/ansible/modules/network/nxos/nxos_portchannel.py index 863e992dd2..1b820f0a72 100644 --- a/lib/ansible/modules/network/nxos/nxos_portchannel.py +++ b/lib/ansible/modules/network/nxos/nxos_portchannel.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages port-channel interfaces. description: - Manages port-channel specific configuration parameters. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -125,162 +124,15 @@ changed: sample: true ''' +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + import collections -import json -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re WARNINGS = [] PARAM_TO_COMMAND_KEYMAP = { 'min_links': 'lacp min-links' @@ -326,75 +178,15 @@ def get_custom_value(arg, config, module): return value -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - -def get_cli_body_ssh(command, response, module): - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show port-channel summary' in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -654,9 +446,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + group = str(module.params['group']) mode = module.params['mode'] min_links = module.params['min_links'] @@ -723,7 +522,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - output = execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state, interface_exist = get_existing(module, args) if 'configure' in cmds: @@ -735,6 +534,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings if WARNINGS: results['warnings'] = WARNINGS @@ -744,3 +544,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_reboot.py b/lib/ansible/modules/network/nxos/nxos_reboot.py index f113873fd0..db24e5b9a7 100644 --- a/lib/ansible/modules/network/nxos/nxos_reboot.py +++ b/lib/ansible/modules/network/nxos/nxos_reboot.py @@ -27,7 +27,6 @@ version_added: 2.2 short_description: Reboot a network device. description: - Reboot a network device. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -58,244 +57,40 @@ rebooted: sample: true ''' -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - +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 reboot(module): - disable_confirmation(module) - execute_show_command(['reload'], module, command_type='cli_show_ascii') - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - body = execute_show(command, module) - elif module.params['transport'] == 'nxapi': - body = execute_show(command, module, command_type=command_type) - - return body - - -def disable_confirmation(module): - command = ['terminal dont-ask'] - body = execute_show_command(command, module, command_type='cli_show_ascii')[0] - + cmds = [ + {'command': 'terminal-dont-ask'}, + {'command': 'reload', 'output': 'text'} + ] + run_commands(module, cmds) def main(): - argument_spec = dict( - confirm=dict(required=True, type='bool'), - include_defaults=dict(default=False), - config=dict(), - save=dict(type='bool', default=False) - ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + argument_spec = {} + argument_spec.update(nxos_argument_spec) - confirm = module.params['confirm'] - if not confirm: - module.fail_json(msg='confirm must be set to true for this ' - 'module to work.') + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) - changed = False - rebooted = False - - reboot(module) + warnings = list() + check_args(module, warnings) + if not module.check_mode: + reboot(module) changed = True - rebooted = True - results = {} - results['changed'] = changed - results['rebooted'] = rebooted + results = { + 'changed': True, + 'warnings': warnings + } module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_rollback.py b/lib/ansible/modules/network/nxos/nxos_rollback.py index a429e1992f..19348e1371 100644 --- a/lib/ansible/modules/network/nxos/nxos_rollback.py +++ b/lib/ansible/modules/network/nxos/nxos_rollback.py @@ -29,7 +29,6 @@ description: - This module offers the ability to set a configuration checkpoint file or rollback to a configuration checkpoint file on Cisco NXOS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -77,159 +76,13 @@ status: ''' -# COMMON CODE FOR MIGRATION import re +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re def execute_commands(cmds, module, command_type=None): @@ -297,7 +150,10 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['checkpoint_file', 'rollback_to']], supports_check_mode=False) @@ -326,3 +182,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_smu.py b/lib/ansible/modules/network/nxos/nxos_smu.py index 76c72f2b0c..86e4229477 100644 --- a/lib/ansible/modules/network/nxos/nxos_smu.py +++ b/lib/ansible/modules/network/nxos/nxos_smu.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Perform SMUs on Cisco NX-OS devices. description: - Perform software maintenance upgrades (SMUs) on Cisco NX-OS devices. -extends_documentation_fragment: nxos author: Gabriele Gerbino (@GGabriele) notes: - The module can only activate and commit a package, @@ -80,202 +79,24 @@ changed: sample: true ''' +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + import time -import json import collections -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +import re def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': cmds = [command] - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -288,28 +109,9 @@ def remote_file_exists(module, dst, file_system='bootflash:'): return True -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - def apply_patch(module, commands): for command in commands: - response = execute_config_command([command], module) + load_config(module, [command]) time.sleep(5) if 'failed' in response: module.fail_json(msg="Operation failed!", response=response) @@ -350,9 +152,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + pkg = module.params['pkg'] file_system = module.params['file_system'] changed = False @@ -382,3 +191,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snapshot.py b/lib/ansible/modules/network/nxos/nxos_snapshot.py index 61dd094b51..fb9a9c64d6 100644 --- a/lib/ansible/modules/network/nxos/nxos_snapshot.py +++ b/lib/ansible/modules/network/nxos/nxos_snapshot.py @@ -29,7 +29,6 @@ description: - Create snapshots of the running states of selected features, add new show commands for snapshot creation, delete and compare existing snapshots. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -209,199 +208,22 @@ changed: sample: true ''' +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + import os -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -535,24 +357,6 @@ def invoke(name, *args, **kwargs): return func(*args, **kwargs) -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_snapshot(module): command = 'show snapshot dump {0}'.format(module.params['snapshot_name']) body = execute_show_command(command, module)[0] @@ -594,11 +398,18 @@ def main(): default=False), path=dict(required=False, type='str', default='./') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['delete_all', 'delete_snapshot']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + action = module.params['action'] comparison_results_file = module.params['comparison_results_file'] @@ -647,7 +458,7 @@ def main(): result['updates'] = [] else: if action_results: - execute_config_command(action_results, module) + load_config(module, action_results) changed = True final_snapshots = invoke('get_existing', module) result['updates'] = action_results @@ -672,3 +483,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_community.py b/lib/ansible/modules/network/nxos/nxos_snmp_community.py index aac8c02ef6..3f42b2f6c0 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_community.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_community.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP community configs. description: - Manages SNMP community configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -98,231 +97,14 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -330,11 +112,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -435,11 +216,18 @@ def main(): acl=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['access', 'group']], mutually_exclusive=[['access', 'group']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + access = module.params['access'] group = module.params['group'] community = module.params['community'] @@ -484,7 +272,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_community(module, community) if 'configure' in cmds: cmds.pop(0) @@ -495,9 +283,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_contact.py b/lib/ansible/modules/network/nxos/nxos_snmp_contact.py index 02601c6de6..e5d8a08d03 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_contact.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_contact.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP contact info. description: - Manages SNMP contact information. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -83,231 +82,14 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -315,11 +97,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -357,9 +138,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + contact = module.params['contact'] state = module.params['state'] @@ -382,7 +170,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_contact(module) if 'configure' in cmds: cmds.pop(0) @@ -393,9 +181,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_host.py b/lib/ansible/modules/network/nxos/nxos_snmp_host.py index 8643b4da7c..c38945a489 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_host.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_host.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP host configuration. description: - Manages SNMP host configuration parameters. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -131,231 +130,14 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -363,11 +145,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -540,9 +321,16 @@ def main(): snmp_type=dict(choices=['trap', 'inform'], default='trap'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + snmp_host = module.params['snmp_host'] community = module.params['community'] @@ -620,7 +408,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_host(snmp_host, module) if 'configure' in cmds: cmds.pop(0) @@ -634,9 +422,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_location.py b/lib/ansible/modules/network/nxos/nxos_snmp_location.py index 7f6e46e033..d415c4e6b8 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_location.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_location.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP location information. description: - Manages SNMP location configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -90,231 +89,14 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -322,11 +104,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -376,9 +157,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + location = module.params['location'] state = module.params['state'] @@ -402,7 +190,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_location(module) if 'configure' in cmds: cmds.pop(0) @@ -413,6 +201,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) @@ -420,3 +209,4 @@ def main(): from ansible.module_utils.basic import * if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_traps.py b/lib/ansible/modules/network/nxos/nxos_snmp_traps.py index d9e8ec5b21..11f829d4f4 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_traps.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_traps.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP traps. description: - Manages SNMP traps configurations. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -101,231 +100,14 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -333,11 +115,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -461,9 +242,16 @@ def main(): 'sysmgr', 'system', 'upgrade', 'vtp', 'all'], required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + group = module.params['group'].lower() state = module.params['state'] @@ -480,7 +268,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_traps(group, module) if 'configure' in cmds: cmds.pop(0) @@ -491,9 +279,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_user.py b/lib/ansible/modules/network/nxos/nxos_snmp_user.py index 5520a7d8dc..5e084bd211 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_user.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_user.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP users for monitoring. description: - Manages SNMP user configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -112,231 +111,14 @@ changed: type: boolean sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module, text=False): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command or text: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show', text=False): @@ -344,11 +126,10 @@ def execute_show_command(command, module, command_type='cli_show', text=False): if 'show run' not in command and text is False: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module, text=text) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -462,11 +243,18 @@ def main(): encrypt=dict(type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['authentication', 'pwd'], ['encrypt', 'privacy']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + user = module.params['user'] group = module.params['group'] pwd = module.params['pwd'] @@ -540,7 +328,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_user(user, module) if 'configure' in cmds: cmds.pop(0) @@ -552,6 +340,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -559,3 +348,4 @@ def main(): if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_static_route.py b/lib/ansible/modules/network/nxos/nxos_static_route.py index ed0bcdd25a..974e902b09 100644 --- a/lib/ansible/modules/network/nxos/nxos_static_route.py +++ b/lib/ansible/modules/network/nxos/nxos_static_route.py @@ -27,7 +27,6 @@ short_description: Manages static route configuration description: - Manages static route configuration author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - If no vrf is supplied, vrf is set to default. - If C(state=absent), the route will be removed, regardless of the @@ -111,159 +110,12 @@ changed: type: boolean sample: true ''' - -# COMMON CODE FOR MIGRATION import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine, dumps -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - if self._device_os == 'junos': - return dumps(section, output='lines') - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def invoke(name, *args, **kwargs): func = globals().get(name) @@ -429,8 +281,13 @@ def main(): save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) state = module.params['state'] @@ -448,12 +305,7 @@ def main(): candidate = CustomNetworkConfig(indent=3) invoke('state_%s' % state, module, candidate, prefix) - try: - response = load_config(module, candidate) - result.update(response) - except Exception: - exc = get_exception() - module.fail_json(msg=str(exc)) + load_config(module, candidate) else: result['updates'] = [] @@ -470,3 +322,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_switchport.py b/lib/ansible/modules/network/nxos/nxos_switchport.py index d02f7e7660..cc05870a40 100644 --- a/lib/ansible/modules/network/nxos/nxos_switchport.py +++ b/lib/ansible/modules/network/nxos/nxos_switchport.py @@ -25,7 +25,6 @@ DOCUMENTATION = ''' module: nxos_switchport version_added: "2.1" short_description: Manages Layer 2 switchport interfaces. -extends_documentation_fragment: nxos description: - Manages Layer 2 interfaces author: Jason Edelman (@jedelman8) @@ -154,161 +153,14 @@ changed: sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re def get_interface_type(interface): """Gets the type of interface @@ -605,86 +457,15 @@ def apply_value_map(value_map, resource): return resource -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -711,12 +492,19 @@ def main(): state=dict(choices=['absent', 'present', 'unconfigured'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['access_vlan', 'trunk_vlans'], ['access_vlan', 'native_vlan'], ['access_vlan', 'trunk_allowed_vlans']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'] mode = module.params['mode'] access_vlan = module.params['access_vlan'] @@ -817,7 +605,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_switchport(interface, module) if 'configure' in cmds: cmds.pop(0) @@ -828,8 +616,10 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_udld.py b/lib/ansible/modules/network/nxos/nxos_udld.py index 06d6d4176b..959eb3672e 100644 --- a/lib/ansible/modules/network/nxos/nxos_udld.py +++ b/lib/ansible/modules/network/nxos/nxos_udld.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages UDLD global configuration params. description: - Manages UDLD global configuration params. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -108,231 +107,14 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -340,11 +122,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -435,10 +216,17 @@ def main(): reset=dict(required=False, type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['aggressive', 'msg_time', 'reset']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + aggressive = module.params['aggressive'] msg_time = module.params['msg_time'] reset = module.params['reset'] @@ -486,7 +274,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_udld_global(module) if 'configure' in cmds: cmds.pop(0) @@ -497,9 +285,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_udld_interface.py b/lib/ansible/modules/network/nxos/nxos_udld_interface.py index 37230e3e2c..a3d5e1ba4c 100644 --- a/lib/ansible/modules/network/nxos/nxos_udld_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_udld_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages UDLD interface configuration params. description: - Manages UDLD interface configuration params. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -107,231 +106,14 @@ changed: ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -339,11 +121,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -466,9 +247,16 @@ def main(): interface=dict(type='str', required=True), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'].lower() mode = module.params['mode'] state = module.params['state'] @@ -500,7 +288,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_udld_interface(module, interface) if 'configure' in cmds: cmds.pop(0) @@ -511,8 +299,10 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_user.py b/lib/ansible/modules/network/nxos/nxos_user.py new file mode 100644 index 0000000000..c527d4bfdd --- /dev/null +++ b/lib/ansible/modules/network/nxos/nxos_user.py @@ -0,0 +1,357 @@ +#!/usr/bin/python +# +# 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 . +# + +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} + +DOCUMENTATION = """ +--- +module: nxos_user +version_added: "2.3" +author: "Peter Sprygada (@privateip)" +short_description: Manage the collection of local users on Nexus devices +description: + - This module provides declarative management of the local usernames + configured on Cisco Nexus devices. It allows playbooks to manage + either individual usernames or the collection of usernames in the + current running config. It also supports purging usernames from the + configuration that are not explicitly defined. +options: + users: + description: + - The set of username objects to be configured on the remote + Cisco Nexus device. The list entries can either be the username + or a hash of username and properties. This argument is mutually + exclusive with the C(name) argument. + required: false + default: null + name: + description: + - The username to be configured on the remote Cisco Nexus + device. This argument accepts a stringv value and is mutually + exclusive with the C(users) argument. + required: false + default: null + update_password: + description: + - Since passwords are encrypted in the device running config, this + argument will instruct the module when to change the password. When + set to C(always), the password will always be updated in the device + and when set to C(on_create) the password will be updated only if + the username is created. + required: false + default: always + choices: ['on_create', 'always'] + role: + description: + - The C(role) argument configures the role for the username in the + device running configuration. The argument accepts a string value + defining the role name. This argument does not check if the role + has been configured on the device. + required: false + default: null + sshkey: + description: + - The C(sshkey) argument defines the SSH public key to configure + for the username. This argument accepts a valid SSH key value. + required: false + default: null + purge: + description: + - The C(purge) argument instructs the module to consider the + resource definition absolute. It will remove any previously + configured usernames on the device with the exception of the + `admin` user which cannot be deleted per nxos constraints. + required: false + default: false + state: + description: + - The C(state) argument configures the state of the username definition + as it relates to the device operational configuration. When set + to I(present), the username(s) should be configured in the device active + configuration and when set to I(absent) the username(s) should not be + in the device active configuration + required: false + default: present + choices: ['present', 'absent'] +""" + +EXAMPLES = """ +- name: create a new user + nxos_user: + name: ansible + sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + state: present + +- name: remove all users except admin + nxos_user: + purge: yes + +- name: set multiple users role + users: + - name: netop + - name: netend + role: network-operator + state: present +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - name ansible + - name ansible password password +start: + description: The time the job started + returned: always + type: str + sample: "2016-11-16 10:38:15.126146" +end: + description: The time the job ended + returned: always + type: str + sample: "2016-11-16 10:38:25.595612" +delta: + description: The time elapsed to perform all operations + returned: always + type: str + sample: "0:00:10.469466" +""" +import re + +from functools import partial + +from ansible.module_utils.nxos import run_commands, load_config +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import string_types, iteritems +from ansible.module_utils.network_common import to_list + +VALID_ROLES = ['network-admin', 'network-operator', 'vdc-admin', 'vdc-operator', + 'priv-15', 'priv-14', 'priv-13', 'priv-12', 'priv-11', 'priv-10', + 'priv-9', 'priv-8', 'priv-7', 'priv-6', 'priv-5', 'priv-4', + 'priv-3', 'priv-2', 'priv-1', 'priv-0'] + + +def validate_roles(value, module): + for item in value: + if item not in VALID_ROLES: + module.fail_json(msg='invalid role specified') + +def map_obj_to_commands(updates, module): + commands = list() + state = module.params['state'] + update_password = module.params['update_password'] + + for update in updates: + want, have = update + + needs_update = lambda x: want.get(x) and (want.get(x) != have.get(x)) + add = lambda x: commands.append('username %s %s' % (want['name'], x)) + remove = lambda x: commands.append('no username %s %s' % (want['name'], x)) + + if want['state'] == 'absent': + commands.append('no username %s' % want['name']) + continue + + if want['state'] == 'present' and not have: + commands.append('username %s' % want['name']) + + if needs_update('password'): + if update_password == 'always' or not have: + add('password %s' % want['password']) + + if needs_update('sshkey'): + add('sshkey %s' % want['sshkey']) + + + if want['roles']: + if have: + for item in set(have['roles']).difference(want['roles']): + remove('role %s' % item) + + for item in set(want['roles']).difference(have['roles']): + add('role %s' % item) + else: + for item in want['roles']: + add('role %s' % item) + + + return commands + +def parse_password(data): + if not data.get('remote_login'): + return '' + +def parse_roles(data): + configured_roles = data.get('TABLE_role')['ROW_role'] + roles = list() + if configured_roles: + for item in to_list(configured_roles): + roles.append(item['role']) + return roles + +def map_config_to_obj(module): + out = run_commands(module, ['show user-account | json']) + data = out[0] + + objects = list() + + for item in to_list(data['TABLE_template']['ROW_template']): + objects.append({ + 'name': item['usr_name'], + 'password': parse_password(item), + 'sshkey': item.get('sshkey_info'), + 'roles': parse_roles(item), + 'state': 'present' + }) + return objects + +def get_param_value(key, item, module): + # if key doesn't exist in the item, get it from module.params + if not item.get(key): + value = module.params[key] + + # if key does exist, do a type check on it to validate it + else: + value_type = module.argument_spec[key].get('type', 'str') + type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] + type_checker(item[key]) + value = item[key] + + return value + +def map_params_to_obj(module): + users = module.params['users'] + if not users: + if not module.params['name'] and module.params['purge']: + return list() + elif not module.params['name']: + module.fail_json(msg='username is required') + else: + collection = [{'name': module.params['name']}] + else: + collection = list() + for item in users: + if not isinstance(item, dict): + collection.append({'name': item}) + elif 'name' not in item: + module.fail_json(msg='name is required') + else: + collection.append(item) + + objects = list() + + for item in collection: + get_value = partial(get_param_value, item=item, module=module) + item.update({ + 'password': get_value('password'), + 'sshkey': get_value('sshkey'), + 'roles': get_value('roles'), + 'state': get_value('state') + }) + + for key, value in iteritems(item): + if value: + # validate the param value (if validator func exists) + validator = globals().get('validate_%s' % key) + if all((value, validator)): + validator(value, module) + + objects.append(item) + + return objects + +def update_objects(want, have): + updates = list() + for entry in want: + item = next((i for i in have if i['name'] == entry['name']), None) + if all((item is None, entry['state'] == 'present')): + updates.append((entry, {})) + elif item: + for key, value in iteritems(entry): + if value and value != item[key]: + updates.append((entry, item)) + return updates + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + users=dict(type='list', no_log=True), + name=dict(), + + password=dict(no_log=True), + update_password=dict(default='always', choices=['on_create', 'always']), + + roles=dict(type='list'), + + sshkey=dict(), + + purge=dict(type='bool', default=False), + state=dict(default='present', choices=['present', 'absent']) + ) + + argument_spec.update(nxos_argument_spec) + + mutually_exclusive = [('name', 'users')] + + module = AnsibleModule(argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True) + + + result = {'changed': False} + + warnings = list() + check_args(module, warnings) + result['warnings'] = warnings + + want = map_params_to_obj(module) + have = map_config_to_obj(module) + + commands = map_obj_to_commands(update_objects(want, have), module) + + if module.params['purge']: + want_users = [x['name'] for x in want] + have_users = [x['name'] for x in have] + for item in set(have_users).difference(want_users): + if item != 'admin': + commands.append('no username %s' % item) + + result['commands'] = commands + + # the nxos cli prevents this by rule so capture it and display + # a nice failure message + if 'no username admin' in commands: + module.fail_json(msg='cannot delete the `admin` account') + + if commands: + if not module.check_mode: + load_config(module, commands) + result['changed'] = True + + module.exit_json(**result) + +if __name__ == '__main__': + main() diff --git a/lib/ansible/modules/network/nxos/nxos_vlan.py b/lib/ansible/modules/network/nxos/nxos_vlan.py index 6e350b89fb..1db2ea9d85 100644 --- a/lib/ansible/modules/network/nxos/nxos_vlan.py +++ b/lib/ansible/modules/network/nxos/nxos_vlan.py @@ -28,7 +28,6 @@ short_description: Manages VLAN resources and attributes. description: - Manages VLAN configurations on NX-OS switches. author: Jason Edelman (@jedelman8) -extends_documentation_fragment: nxos options: vlan_id: description: @@ -153,163 +152,15 @@ changed: sample: true ''' +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 -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.nxos import run_commands, load_config, get_config +from ansible.module_utils.basic import AnsibleModule def vlan_range_to_list(vlans): result = [] @@ -396,8 +247,7 @@ def get_vlan_config_commands(vlan, vid): def get_list_of_vlans(module): - command = 'show vlan' - body = execute_show_command(command, module) + body = run_commands(module, ['show vlan | json']) vlan_list = [] vlan_table = body[0].get('TABLE_vlanbrief')['ROW_vlanbrief'] @@ -411,8 +261,10 @@ def get_list_of_vlans(module): def get_vni(vlanid, module): - command = 'show run all | section vlan.{0}'.format(vlanid) - body = execute_show_command(command, module, command_type='cli_show_ascii')[0] + flags = str('all | section vlan.{0}'.format(vlanid)).split(' ') + body = get_config(module, flags=flags) + #command = 'show run all | section vlan.{0}'.format(vlanid) + #body = execute_show_command(command, module, command_type='cli_show_ascii')[0] value = '' if body: REGEX = re.compile(r'(?:vn-segment\s)(?P.*)$', re.M) @@ -424,10 +276,11 @@ def get_vni(vlanid, module): def get_vlan(vlanid, module): """Get instance of VLAN as a dictionary """ + command = 'show vlan id %s | json' % vlanid + body = run_commands(module, [command]) - command = 'show vlan id ' + vlanid - - body = execute_show_command(command, module) + #command = 'show vlan id ' + vlanid + #body = execute_show_command(command, module) try: vlan_table = body[0]['TABLE_vlanbriefid']['ROW_vlanbriefid'] @@ -469,90 +322,6 @@ def apply_value_map(value_map, resource): resource[key] = value[resource.get(key)] return resource - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'show run' in command or response[0] == '\n': - body = response - elif 'xml' in response[0]: - body = [] - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - if 'show run' not in command: - command += ' | json' - cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) - elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - - return body - - def main(): argument_spec = dict( vlan_id=dict(required=False, type='str'), @@ -567,10 +336,23 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - mutually_exclusive=[['vlan_range', 'name'], - ['vlan_id', 'vlan_range']], - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + mutually_exclusive=[['vlan_range', 'name'], + ['vlan_id', 'vlan_range']], + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) + + + warnings = list() + check_args(module, warnings) vlan_range = module.params['vlan_range'] vlan_id = module.params['vlan_id'] @@ -636,7 +418,7 @@ def main(): module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True end_state_vlans_list = numerical_sort(get_list_of_vlans(module)) if 'configure' in commands: @@ -653,9 +435,12 @@ def main(): results['end_state_vlans_list'] = end_state_vlans_list results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vpc.py b/lib/ansible/modules/network/nxos/nxos_vpc.py index 87bde5ad67..9e243d8ae7 100644 --- a/lib/ansible/modules/network/nxos/nxos_vpc.py +++ b/lib/ansible/modules/network/nxos/nxos_vpc.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages global VPC configuration description: - Manages global VPC configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -145,243 +144,20 @@ changed: sample: true ''' -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. - """ - if '^' == response[0]: - body = [] - elif 'running' in command: - body = response - else: - if command in response[0]: - response = [response[0].split(command)[1]] - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if "section" not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -577,9 +353,15 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + domain = module.params['domain'] role_priority = module.params['role_priority'] system_priority = module.params['system_priority'] @@ -640,7 +422,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vpc(module) if 'configure' in cmds: cmds.pop(0) @@ -651,9 +433,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py index 2ac23411a2..76bb532b49 100644 --- a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages interface VPC configuration description: - Manages interface VPC configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,240 +96,19 @@ changed: ''' -import collections -import json - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - response = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return response - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. - """ - if '^' == response[0]: - body = [] - elif 'running' in command or 'xml' in response[0]: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -485,10 +263,17 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['vpc', 'peer_link']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + portchannel = module.params['portchannel'] vpc = module.params['vpc'] peer_link = module.params['peer_link'] @@ -570,7 +355,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - output = execute_config_command(cmds, module) + load_config(module, cmds) if module.params['transport'] == 'cli': output = ' '.join(output) if 'error' in output.lower(): @@ -585,9 +370,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf.py b/lib/ansible/modules/network/nxos/nxos_vrf.py index 899c4722ef..2f70a89c51 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages global VRF configuration. description: - Manages global VRF configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -117,238 +116,23 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrf(module, command, response): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when using multiple |. - """ - command_splitted = command.split('|') - if len(command_splitted) > 2 or 'show run' in command: - body = response - elif 'xml' in response[0] or response[0] == '\n': - body = [] - else: - body = [json.loads(response[0])] - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': + transport = module.params['provider']['transport'] + if transport in ['cli', None]: if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrf(module, command, response) - elif module.params['transport'] == 'nxapi': + body = run_commands(module, cmds) + else: cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -457,9 +241,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vrf = module.params['vrf'] admin_state = module.params['admin_state'].lower() description = module.params['description'] @@ -512,7 +303,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True end_state = get_vrf(vrf, module) if 'configure' in commands: @@ -524,9 +315,11 @@ def main(): results['end_state'] = end_state results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_af.py b/lib/ansible/modules/network/nxos/nxos_vrf_af.py index 28d4e29c11..91072ec6ab 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf_af.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf_af.py @@ -28,7 +28,6 @@ short_description: Manages VRF AF. description: - Manages VRF AF author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default, where supported, restores params default value. options: @@ -104,159 +103,12 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = ['route_target_both_auto_evpn'] PARAM_TO_COMMAND_KEYMAP = { @@ -378,9 +230,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ @@ -434,3 +293,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py index b007040102..d6ea1a1043 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages interface specific VRF configuration. description: - Manages interface specific VRF configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,240 +96,25 @@ changed: type: boolean sample: true ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError +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 +from ansible.module_utils.netcfg import CustomNetworkConfig -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE WARNINGS = [] -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrf_interface(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. As such, - we assume if '^' is found in response, it is an invalid command. Instead, - the output will be a raw string when issuing commands containing 'show run'. - """ - if '^' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - body = [json.loads(response[0])] - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrf_interface(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -428,9 +212,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vrf = module.params['vrf'] interface = module.params['interface'].lower() state = module.params['state'] @@ -486,7 +277,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True changed_vrf = get_interface_info(interface, module) end_state = dict(interface=interface, vrf=changed_vrf) @@ -508,3 +299,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrrp.py b/lib/ansible/modules/network/nxos/nxos_vrrp.py index 86f6a22375..ec6be83a08 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrrp.py +++ b/lib/ansible/modules/network/nxos/nxos_vrrp.py @@ -28,7 +28,6 @@ version_added: "2.1" short_description: Manages VRRP configuration on NX-OS switches. description: - Manages VRRP configuration on NX-OS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -135,245 +134,21 @@ changed: type: boolean sample: true ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrrp(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - +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 +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrrp(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -587,9 +362,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'].lower() group = module.params['group'] @@ -648,7 +430,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = get_existing_vrrp(interface, group, module, name) if 'configure' in cmds: @@ -659,6 +441,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -666,3 +449,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_domain.py b/lib/ansible/modules/network/nxos/nxos_vtp_domain.py index abd126858f..4ef6525a69 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_domain.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_domain.py @@ -26,7 +26,6 @@ version_added: "2.2" short_description: Manages VTP domain configuration. description: - Manages VTP domain configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -84,243 +83,22 @@ changed: ''' -import json - -# COMMON CODE FOR MIGRATION +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 +from ansible.module_utils.netcfg import CustomNetworkConfig import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -380,9 +158,16 @@ def main(): argument_spec = dict( domain=dict(type='str', required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + domain = module.params['domain'] existing = get_vtp_config(module) @@ -404,7 +189,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -415,9 +200,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_password.py b/lib/ansible/modules/network/nxos/nxos_vtp_password.py index c1cfe1337e..cda74f6358 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_password.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_password.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages VTP password configuration. description: - Manages VTP password configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -101,243 +100,22 @@ changed: sample: true ''' -import json - -# COMMON CODE FOR MIGRATION +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 +from ansible.module_utils.netcfg import CustomNetworkConfig import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -412,9 +190,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vtp_password = module.params['vtp_password'] or None state = module.params['state'] @@ -461,7 +246,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -472,9 +257,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_version.py b/lib/ansible/modules/network/nxos/nxos_vtp_version.py index 0754c3bb26..c61df0bc25 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_version.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_version.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages VTP version configuration. description: - Manages VTP version configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -79,231 +78,14 @@ changed: type: boolean sample: true ''' -import json +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 +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -311,11 +93,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -375,9 +156,16 @@ def main(): argument_spec = dict( version=dict(type='str', choices=['1', '2'], required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + version = module.params['version'] existing = get_vtp_config(module) @@ -399,7 +187,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -410,9 +198,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py index 08ac7692c7..eac3530471 100644 --- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py +++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py @@ -29,7 +29,6 @@ description: - Manages VXLAN Network Virtualization Endpoint (NVE) overlay interface that terminates VXLAN tunnels. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - The module is used to manage NVE properties, not to create NVE interfaces. Use M(nxos_interface) if you wish to do so. @@ -124,159 +123,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = [ 'shutdown', @@ -458,9 +309,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'].lower() @@ -528,3 +386,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py index 4abfd33f8c..3e79eae8e8 100644 --- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py +++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py @@ -29,7 +29,6 @@ description: - Creates a Virtual Network Identifier member (VNI) for an NVE overlay interface. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - default, where supported, restores params default value. options: @@ -143,159 +142,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +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 +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = ['suppress_arp'] PARAM_TO_COMMAND_KEYMAP = { @@ -496,9 +347,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + if module.params['assoc_vrf']: mutually_exclusive_params = ['multicast_group', 'suppress_arp', @@ -587,3 +445,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/plugins/action/nxos.py b/lib/ansible/plugins/action/nxos.py new file mode 100644 index 0000000000..c6c80a3ad0 --- /dev/null +++ b/lib/ansible/plugins/action/nxos.py @@ -0,0 +1,112 @@ +# +# (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 . +# +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import sys +import copy + +from ansible.plugins.action.normal import ActionModule as _ActionModule +from ansible.utils.path import unfrackpath +from ansible.plugins import connection_loader +from ansible.compat.six import iteritems +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.basic import AnsibleFallbackNotFound +from ansible.module_utils._text import to_bytes + +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + provider = self.load_provider() + transport = provider['transport'] + + if not transport or 'cli' in transport: + pc = copy.deepcopy(self._play_context) + pc.connection = 'network_cli' + pc.network_os = 'nxos' + pc.port = provider['port'] or self._play_context.port or 22 + pc.remote_user = provider['username'] or self._play_context.connection_user + pc.password = provider['password'] or self._play_context.password + + socket_path = self._get_socket_path(pc) + if not os.path.exists(socket_path): + # start the connection if it isn't started + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection.exec_command('EXEC: show version') + + task_vars['ansible_socket'] = socket_path + + else: + if provider['host'] is None: + self._task.args['host'] = self._play_context.remote_addr + if provider['username'] is None: + self._task.args['username'] = self._play_context.connection_user + if provider['password'] is None: + self._task.args['password'] = self._play_context.password + if provider['timeout'] is None: + self._task.args['timeout'] = self._play_context.timeout + if task_vars.get('nxapi_use_ssl'): + self._task.args['use_ssl'] = task_vars['nxapi_use_ssl'] + if task_vars.get('nxapi_validate_certs'): + self._task.args['validate_certs'] = task_vars['nxapi_validate_certs'] + + + transport = self._task.args.get('transport') + if not transport: + transport = self._task.args.get('provider', {}).get('transport') + self._task.args['transport'] = transport or 'cli' + + return super(ActionModule, self).run(tmp, task_vars) + + def _get_socket_path(self, play_context): + ssh = connection_loader.get('ssh', class_only=True) + cp = ssh._create_control_path(play_context.remote_addr, play_context.port, play_context.remote_user) + path = unfrackpath("$HOME/.ansible/pc") + return cp % dict(directory=path) + + def load_provider(self): + provider = self._task.args.get('provider', {}) + for key, value in iteritems(nxos_argument_spec): + if key != 'provider' and key not in provider: + if key in self._task.args: + provider[key] = self._task.args[key] + elif 'fallback' in value: + provider[key] = self._fallback(value['fallback']) + elif key not in provider: + provider[key] = None + return provider + + def _fallback(self, fallback): + strategy = fallback[0] + args = [] + kwargs = {} + + for item in fallback[1:]: + if isinstance(item, dict): + kwargs = item + else: + args = item + try: + return strategy(*args, **kwargs) + except AnsibleFallbackNotFound: + pass + + diff --git a/lib/ansible/plugins/action/nxos_config.py b/lib/ansible/plugins/action/nxos_config.py index ffcb0f057f..f3b0e995c4 100644 --- a/lib/ansible/plugins/action/nxos_config.py +++ b/lib/ansible/plugins/action/nxos_config.py @@ -19,10 +19,95 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible.plugins.action import ActionBase -from ansible.plugins.action.net_config import ActionModule as NetActionModule +import os +import re +import time +import glob -class ActionModule(NetActionModule, ActionBase): - pass +from ansible.plugins.action.nxos import ActionModule as _ActionModule +from ansible.module_utils._text import to_text +from ansible.module_utils.six.moves.urllib.parse import urlsplit +from ansible.utils.vars import merge_hash +PRIVATE_KEYS_RE = re.compile('__.+__') + + +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + if self._task.args.get('src'): + try: + self._handle_template() + except ValueError as exc: + return dict(failed=True, msg=exc.message) + + result = super(ActionModule, self).run(tmp, task_vars) + + if self._task.args.get('backup') and result.get('__backup__'): + # User requested backup and no error occurred in module. + # NOTE: If there is a parameter error, _backup key may not be in results. + filepath = self._write_backup(task_vars['inventory_hostname'], + result['__backup__']) + + result['backup_path'] = filepath + + # strip out any keys that have two leading and two trailing + # underscore characters + for key in result.keys(): + if PRIVATE_KEYS_RE.match(key): + del result[key] + + return result + + def _get_working_path(self): + cwd = self._loader.get_basedir() + if self._task._role is not None: + cwd = self._task._role._role_path + return cwd + + def _write_backup(self, host, contents): + backup_path = self._get_working_path() + '/backup' + if not os.path.exists(backup_path): + os.mkdir(backup_path) + for fn in glob.glob('%s/%s*' % (backup_path, host)): + os.remove(fn) + tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time())) + filename = '%s/%s_config.%s' % (backup_path, host, tstamp) + open(filename, 'w').write(contents) + return filename + + def _handle_template(self): + src = self._task.args.get('src') + working_path = self._get_working_path() + + if os.path.isabs(src) or urlsplit('src').scheme: + source = src + else: + source = self._loader.path_dwim_relative(working_path, 'templates', src) + if not source: + source = self._loader.path_dwim_relative(working_path, src) + + if not os.path.exists(source): + raise ValueError('path specified in src not found') + + try: + with open(source, 'r') as f: + template_data = to_text(f.read()) + except IOError: + return dict(failed=True, msg='unable to load src file') + + # Create a template search path in the following order: + # [working_path, self_role_path, dependent_role_paths, dirname(source)] + searchpath = [working_path] + if self._task._role is not None: + searchpath.append(self._task._role._role_path) + if hasattr(self._task, "_block:"): + dep_chain = self._task._block.get_dep_chain() + if dep_chain is not None: + for role in dep_chain: + searchpath.append(role._role_path) + searchpath.append(os.path.dirname(source)) + self._templar.environment.loader.searchpath = searchpath + self._task.args['src'] = self._templar.template(template_data) diff --git a/lib/ansible/plugins/action/nxos_template.py b/lib/ansible/plugins/action/nxos_template.py index 2b63234f16..47f7d55a78 100644 --- a/lib/ansible/plugins/action/nxos_template.py +++ b/lib/ansible/plugins/action/nxos_template.py @@ -19,9 +19,84 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible.plugins.action import ActionBase -from ansible.plugins.action.net_template import ActionModule as NetActionModule +import os +import time +import glob +import urlparse -class ActionModule(NetActionModule, ActionBase): - pass +from ansible.module_utils._text import to_text +from ansible.plugins.action.nxos import ActionModule as _ActionModule +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + try: + self._handle_template() + except (ValueError, AttributeError) as exc: + return dict(failed=True, msg=exc.message) + + result = super(ActionModule, self).run(tmp, task_vars) + + if self._task.args.get('backup') and result.get('__backup__'): + # User requested backup and no error occurred in module. + # NOTE: If there is a parameter error, __backup__ key may not be in results. + self._write_backup(task_vars['inventory_hostname'], result['__backup__']) + + if '__backup__' in result: + del result['__backup__'] + + return result + + def _get_working_path(self): + cwd = self._loader.get_basedir() + if self._task._role is not None: + cwd = self._task._role._role_path + return cwd + + def _write_backup(self, host, contents): + backup_path = self._get_working_path() + '/backup' + if not os.path.exists(backup_path): + os.mkdir(backup_path) + for fn in glob.glob('%s/%s*' % (backup_path, host)): + os.remove(fn) + tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time())) + filename = '%s/%s_config.%s' % (backup_path, host, tstamp) + open(filename, 'w').write(contents) + + def _handle_template(self): + src = self._task.args.get('src') + if not src: + raise ValueError('missing required arguments: src') + + working_path = self._get_working_path() + + if os.path.isabs(src) or urlparse.urlsplit(src).scheme: + source = src + else: + source = self._loader.path_dwim_relative(working_path, 'templates', src) + if not source: + source = self._loader.path_dwim_relative(working_path, src) + + if not os.path.exists(source): + return + + try: + with open(source, 'r') as f: + template_data = to_text(f.read()) + except IOError: + return dict(failed=True, msg='unable to load src file') + + # Create a template search path in the following order: + # [working_path, self_role_path, dependent_role_paths, dirname(source)] + searchpath = [working_path] + if self._task._role is not None: + searchpath.append(self._task._role._role_path) + if hasattr(self._task, "_block:"): + dep_chain = self._task._block.get_dep_chain() + if dep_chain is not None: + for role in dep_chain: + searchpath.append(role._role_path) + searchpath.append(os.path.dirname(source)) + self._templar.environment.loader.searchpath = searchpath + self._task.args['src'] = self._templar.template(template_data) diff --git a/lib/ansible/plugins/terminal/nxos.py b/lib/ansible/plugins/terminal/nxos.py index e23192f077..21c1e2d680 100644 --- a/lib/ansible/plugins/terminal/nxos.py +++ b/lib/ansible/plugins/terminal/nxos.py @@ -52,11 +52,3 @@ class TerminalModule(TerminalBase): except AnsibleConnectionFailure: raise AnsibleConnectionFailure('unable to set terminal parameters') - @staticmethod - def guess_network_os(conn): - stdin, stdout, stderr = conn.exec_command('show version') - if 'NX-OS' in stdout.read(): - return 'nxos' - - -