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 | 155 +++--- .../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 | 141 +++--- .../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 | 310 ++++++------ 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, 2298 insertions(+), 12930 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 90180085e3c..abdbffd7843 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 0360747d896..fa24e0b4118 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 + +_DEVICE_CONNECTION = None + +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 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() -add_argument('use_ssl', dict(default=False, type='bool')) -add_argument('validate_certs', dict(default=True, type='bool')) + 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() -class NxapiConfigMixin(object): + 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'] - 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] + rc, out, err = self.exec_command(cmd) - 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]) + if check_rc and rc != 0: + self._module.fail_json(msg=err) - try: - self.configure(config) - except NetworkError: - self.load_checkpoint(checkpoint) - raise + try: + out = self._module.from_json(out) + except ValueError: + out = str(out).strip() - try: - self.execute(['no checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['no checkpoint %s' % checkpoint]) + responses.append(out) + return responses - 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_config(self, config): + """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) - 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]) + for cmd in config: + rc, out, err = self.exec_command(cmd) + if rc != 0: + self._module.fail_json(msg=err) + self.exec_command('end') -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() - - while commands: - stack.append(commands.popleft()) - if len(stack) == 10: - body = self._get_body(stack, output) - data = self._jsonify(body) + if output != 'config': + commands = collections.deque(commands) + stack = list() + requests = list() + + 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) + + for item in to_list(commands): + if is_json(item['command']): + item['command'] = str(item['command']).split('|')[0] + item['output'] = 'json' - output = cmd.output - cmds.append(str(cmd)) + if all((output == 'json', item['output'] == 'text')) or all((output =='text', item['output'] == 'json')): + responses.extend(_send(queue, output)) + queue = list() - if cmds: - responses.extend(self.execute(cmds, output=output)) + output = item['output'] or 'json' + queue.append(item['command']) + + if queue: + responses.extend(_send(queue, output)) return responses + 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') - ### Config methods ### - def configure(self, commands): - commands = to_list(commands) - return self.execute(commands, output='config') +is_json = lambda x: str(x).endswith('| json') +is_text = lambda x: not is_json - 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) - - -class Cli(NxapiConfigMixin, 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 connect(self, params, **kwargs): - super(Cli, self).connect(params, kickstart=False, **kwargs) - self.shell.send('terminal length 0') - - ### Command methods ### - - 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 is_nxapi(module): + transport = module.params['transport'] + provider_transport = (module.params['provider'] or {}).get('transport') + return 'nxapi' in (transport, provider_transport) - ### Config methods ### +def to_command(module, commands): + if is_nxapi(module): + default_output = 'json' + else: + default_output = 'text' - def configure(self, commands, **kwargs): - commands = prepare_config(commands) - responses = self.execute(commands) - responses.pop(0) - return responses + transform = ComplexList(dict( + command=dict(key=True), + output=dict(default=default_output), + prompt=dict(), + response=dict() + ), module) + + commands = transform(to_list(commands)) -Cli = register_transport('cli', default=True)(Cli) + for index, item in enumerate(commands): + if is_json(item['command']): + item['output'] = 'json' + elif is_text(item['command']): + item['output'] = 'text' +def get_config(module, flags=[]): + conn = get_connection(module) + return conn.get_config(flags) -def prepare_config(commands): - prepared = ['config'] - prepared.extend(to_list(commands)) - prepared.append('end') - return prepared +def run_commands(module, commands, check_rc=True): + conn = get_connection(module) + to_command(module, commands) + return conn.run_commands(commands) +def load_config(module, config): + conn = get_connection(module) + return conn.load_config(config) -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 65623b6abe5..00000000000 --- 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 51ed607a252..ef0c685b612 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 47a8b3f0040..ee2732564bb 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 cf2dc9a7fb6..1ac359241c5 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 f5219aa06d1..7c74d2eaad5 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 8c4cc10d2a7..62362ef8c14 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 08f603f519e..e8041400847 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 960e2d966f4..7446559dabb 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 ebb886760ad..f18a3f9daa2 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 b90034a09e6..5daeb442fb3 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 - -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 + lines.append(item) + return lines + +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() + check_args(module, warnings) + commands = parse_commands(module, warnings) + result['warnings'] = warnings - 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) + wait_for = module.params['wait_for'] or list() try: - for item in conditionals: - runner.add_conditional(item) - except AddConditionError: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError: exc = get_exception() - module.fail_json(msg=str(exc), condition=exc.condition) + module.fail_json(msg=str(exc)) - runner.retries = module.params['retries'] - runner.interval = module.params['interval'] - runner.match = module.params['match'] + retries = module.params['retries'] + interval = module.params['interval'] + 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) + while retries > 0: + responses = run_commands(module, commands) - result = dict(changed=False) + for item in list(conditionals): + if item(responses): + if match == 'any': + conditionals = list() + break + conditionals.remove(item) - 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) + if not conditionals: + break - result['warnings'] = warnings - result['stdout_lines'] = list(to_lines(result['stdout'])) + 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 2355ec37d89..fbb3ed7751a 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 20f6f8784e7..befbb64c356 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 08c73d69114..a62f28fd3c5 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 b3fd2a7fd9d..4e1d4f1ebb8 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): + COMMANDS = frozenset() + + def __init__(self, module): self.module = module - self.runner = runner self.facts = dict() - self.commands() + self.responses = None - def commands(self): - raise NotImplementedError + 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)) - - 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)) + instances.append(FACT_SUBSETS[key](module)) + + 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 3e23d22d08a..336ee7085d6 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 8f241658f0d..891f32e1239 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 cb22ae12d40..5d091a70e58 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 5d7751141b9..fa5328f9ce7 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 c5f766ca7a2..5854be331ca 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 7cc36bb3921..1262a649e36 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 1432c4d47f3..65c3eacf270 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 f63b75f0ed8..065369a50b1 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 f0ba09be7c2..59640dc8df9 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 fafbae89ea9..93532df3fca 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 +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.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 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 36fbf5cd282..61f22b53637 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 e2ae39955ce..e36a51aed28 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 35b3303c36d..2299e79134f 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 721fc473f74..27285bf6911 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 4d094c49cd6..43811c12d80 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 0bf1fb70f72..23be4f8c733 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,231 +103,13 @@ 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'): @@ -336,11 +117,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 @@ -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 9a3985a92ff..5108b24d522 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 -PRIVATE_KEYS_RE = re.compile('__.+__') +from functools import partial -def invoke(name, *args, **kwargs): - func = globals().get(name) - if func: - return func(*args, **kwargs) +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 get_instance(module): - instance = dict(state='absent') - try: - resp = module.cli('show nxapi', 'json') - except NetworkError: - return instance +def check_args(module, warnings): + nxos_check_args(module, warnings) - instance['state'] = 'present' - - instance['http'] = 'http_port' in resp[0] - instance['http_port'] = resp[0].get('http_port') or 80 - - instance['https'] = 'https_port' in resp[0] - instance['https_port'] = resp[0].get('https_port') or 443 + state = module.params['state'] - instance['sandbox'] = resp[0]['sandbox_status'] + 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') - return instance + if module.params['transport'] == 'nxapi': + module.fail_json(msg='module not supported over nxapi transport') -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) + for key in ['config']: + if module.params[key]: + warnings.append('argument %s is deprecated and will be ignored' % key) -def absent(module, instance, commands): - if instance['state'] != 'absent': - commands.append('no feature nxapi') + return warnings -def set_http(module, instance, commands): - port = module.params['http_port'] - if not 0 <= port <= 65535: +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates + + needs_update = lambda x: want.get(x) is not None and (want.get(x) != have.get(x)) + + if needs_update('state'): + if want['state'] == 'absent': + return ['no feature nxapi'] + commands.append('feature nxapi') + + 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 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] +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'] + } + 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'), - - https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'), - https_port=dict(default=443, type='int', setter='set_https'), + http=dict(aliases=['enable_http'], type='bool'), + http_port=dict(type='int'), - sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'), + https=dict(aliases=['enable_https'], type='bool'), + https_port=dict(type='int'), - # 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, - supports_check_mode=True) + argument_spec.update(nxos_argument_spec) - state = module.params['state'] + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) - warnings = list() - result = dict(changed=False, warnings=warnings) + result = {'changed': False} - 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') + warnings = list() + check_args(module, warnings) + result['warnings'] = warnings - commands = list() - instance = get_instance(module) + want = map_params_to_obj(module) + have = map_config_to_obj(module) - invoke(state, module, instance, commands) + commands = map_obj_to_commands((want, have), module) + result['commands'] = commands - try: - load(module, commands, result) - except (ValueError, NetworkError): - load_checkpoint(module, result) - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) + if commands: + if not module.check_mode: + load_config(module, commands) + result['changed'] = True - 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 ead87ee71d6..a0a98ae942b 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 81d77e1c137..c0edc9a42d4 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 5d31b049a8f..01ba9d92786 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 74e679bbaf3..d3f13913d3c 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 ba90299a9ef..4db51f94bec 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 f32bee8dfb2..3a6287bb007 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 3a9b628f943..a3a7cc7419a 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 863e992dd2b..1b820f0a72f 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 f113873fd04..db24e5b9a7b 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) - - confirm = module.params['confirm'] - if not confirm: - module.fail_json(msg='confirm must be set to true for this ' - 'module to work.') + argument_spec = {} + argument_spec.update(nxos_argument_spec) - changed = False - rebooted = False + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) - 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 a429e1992f9..19348e1371d 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 76c72f2b0cc..86e4229477e 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 61dd094b517..fb9a9c64d68 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 aac8c02ef6e..3f42b2f6c0e 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 +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 02601c6de64..e5d8a08d03f 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 +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 8643b4da7c7..c38945a4893 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 - -# 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 +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(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 +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 7f6e46e0330..d415c4e6b8f 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 - -# 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 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 +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 d9e8ec5b213..11f829d4f4f 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 +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 5520a7d8dc9..5e084bd2119 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 +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 ed0bcdd25a3..974e902b099 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 d02f7e76602..cc05870a404 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 +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 06d6d4176b1..959eb3672e5 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 +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 37230e3e2cc..a3d5e1ba4c8 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 +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 00000000000..c527d4bfdd8 --- /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 6e350b89fb7..1db2ea9d85d 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 87bde5ad67d..9e243d8ae7f 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 2ac23411a2e..76bb532b49b 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 899c4722ef5..2f70a89c514 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 28d4e29c11e..91072ec6abe 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 b007040102d..d6ea1a10432 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 - -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']) +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 - 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 86f6a223755..ec6be83a081 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 abd126858f4..4ef6525a696 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 c1cfe1337e5..cda74f63587 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 0754c3bb261..c61df0bc253 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 +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 08ac7692c75..eac35304719 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 4abfd33f8c4..3e79eae8e8e 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 00000000000..c6c80a3ad03 --- /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 ffcb0f057f8..f3b0e995c4e 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 2b63234f169..47f7d55a789 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 e23192f0774..21c1e2d6806 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' - - -