diff --git a/lib/ansible/module_utils/netcfg.py b/lib/ansible/module_utils/netcfg.py index 90180085e3..abdbffd784 100644 --- a/lib/ansible/module_utils/netcfg.py +++ b/lib/ansible/module_utils/netcfg.py @@ -28,6 +28,7 @@ import re from ansible.module_utils.six.moves import zip +from ansible.module_utils.network_common import to_list DEFAULT_COMMENT_TOKENS = ['#', '!', '/*', '*/'] @@ -361,3 +362,91 @@ class NetworkConfig(object): self.items.append(item) +class CustomNetworkConfig(NetworkConfig): + + def expand_section(self, configobj, S=None): + if S is None: + S = list() + S.append(configobj) + for child in configobj.children: + if child in S: + continue + self.expand_section(child, S) + return S + + def get_object(self, path): + for item in self.items: + if item.text == path[-1]: + parents = [p.text for p in item.parents] + if parents == path[:-1]: + return item + + def to_block(self, section): + return '\n'.join([item.raw for item in section]) + + def get_section(self, path): + try: + section = self.get_section_objects(path) + return self.to_block(section) + except ValueError: + return list() + + def get_section_objects(self, path): + if not isinstance(path, list): + path = [path] + obj = self.get_object(path) + if not obj: + raise ValueError('path does not exist in config') + return self.expand_section(obj) + + + def add(self, lines, parents=None): + """Adds one or lines of configuration + """ + + ancestors = list() + offset = 0 + obj = None + + ## global config command + if not parents: + for line in to_list(lines): + item = ConfigLine(line) + item.raw = line + if item not in self.items: + self.items.append(item) + + else: + for index, p in enumerate(parents): + try: + i = index + 1 + obj = self.get_section_objects(parents[:i])[0] + ancestors.append(obj) + + except ValueError: + # add parent to config + offset = index * self.indent + obj = ConfigLine(p) + obj.raw = p.rjust(len(p) + offset) + if ancestors: + obj.parents = list(ancestors) + ancestors[-1].children.append(obj) + self.items.append(obj) + ancestors.append(obj) + + # add child objects + for line in to_list(lines): + # check if child already exists + for child in ancestors[-1].children: + if child.text == line: + break + else: + offset = len(parents) * self.indent + item = ConfigLine(line) + item.raw = line.rjust(len(line) + offset) + item.parents = ancestors + ancestors[-1].children.append(item) + self.items.append(item) + + + diff --git a/lib/ansible/module_utils/nxos.py b/lib/ansible/module_utils/nxos.py index 0360747d89..fa24e0b411 100644 --- a/lib/ansible/module_utils/nxos.py +++ b/lib/ansible/module_utils/nxos.py @@ -1,80 +1,150 @@ # -# (c) 2015 Peter Sprygada, +# This code is part of Ansible, but is an independent component. # -# This file is part of Ansible +# This particular file snippet, and this file snippet only, is BSD licensed. +# Modules you write using this snippet, which is embedded dynamically by Ansible +# still belong to the author of the module, and may assign their own license +# to the complete work. # -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# (c) 2017 Red Hat, Inc. # -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: # -# You should have received a copy of the GNU General Public License -# along with Ansible. If not, see . +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # - import re -import time import collections -from ansible.module_utils.basic import json, json_dict_bytes_to_unicode -from ansible.module_utils.network import ModuleStub, NetworkError, NetworkModule -from ansible.module_utils.network import add_argument, register_transport, to_list -from ansible.module_utils.shell import CliBase -from ansible.module_utils.urls import fetch_url, url_argument_spec +from ansible.module_utils.basic import env_fallback +from ansible.module_utils.network_common import to_list, ComplexList +from ansible.module_utils.connection import exec_command +from ansible.module_utils.six import iteritems +from ansible.module_utils.urls import fetch_url -add_argument('use_ssl', dict(default=False, type='bool')) -add_argument('validate_certs', dict(default=True, type='bool')) +_DEVICE_CONNECTION = None -class NxapiConfigMixin(object): +nxos_argument_spec = { + 'host': dict(), + 'port': dict(type='int'), + 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), + 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), + 'use_ssl': dict(type='bool'), + 'validate_certs': dict(type='bool'), + 'timeout': dict(type='int'), + 'provider': dict(type='dict'), + 'transport': dict(choices=['cli', 'nxapi']) +} - def get_config(self, include_defaults=False, **kwargs): - cmd = 'show running-config' - if include_defaults: - cmd += ' all' - if isinstance(self, Nxapi): - return self.execute([cmd], output='text')[0] - else: - return self.execute([cmd])[0] +def check_args(module, warnings): + provider = module.params['provider'] or {} + for key in nxos_argument_spec: + if key not in ['provider', 'transport'] and module.params[key]: + warnings.append('argument %s has been deprecated and will be ' + 'removed in a future version' % key) + +def load_params(module): + provider = module.params.get('provider') or dict() + for key, value in iteritems(provider): + if key in nxos_argument_spec: + if module.params.get(key) is None and value is not None: + module.params[key] = value + +def get_connection(module): + global _DEVICE_CONNECTION + if not _DEVICE_CONNECTION: + load_params(module) + transport = module.params['transport'] + if transport == 'cli': + conn = Cli(module) + elif transport == 'nxapi': + conn = Nxapi(module) + _DEVICE_CONNECTION = conn + return _DEVICE_CONNECTION + +class Cli: + + def __init__(self, module): + self._module = module + self._device_configs = {} + + def exec_command(self, command): + if isinstance(command, dict): + command = self._module.jsonify(command) + return exec_command(self._module, command) + + def get_config(self, flags=[]): + """Retrieves the current config from the device or cache + """ + cmd = 'show running-config ' + cmd += ' '.join(flags) + cmd = cmd.strip() + + try: + return self._device_configs[cmd] + except KeyError: + rc, out, err = self.exec_command(cmd) + if rc != 0: + self._module.fail_json(msg=err) + cfg = str(out).strip() + self._device_configs[cmd] = cfg + return cfg + + def run_commands(self, commands, check_rc=True): + """Run list of commands on remote device and return results + """ + responses = list() + + for item in to_list(commands): + if item['output'] == 'json' and not is_json(item['command']): + cmd = '%s | json' % item['command'] + elif item['output'] == 'text' and is_json(item['command']): + cmd = item['command'].split('|')[0] + else: + cmd = item['command'] + + rc, out, err = self.exec_command(cmd) + + if check_rc and rc != 0: + self._module.fail_json(msg=err) + + try: + out = self._module.from_json(out) + except ValueError: + out = str(out).strip() + + responses.append(out) + return responses def load_config(self, config): - checkpoint = 'ansible_%s' % int(time.time()) - try: - self.execute(['checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['checkpoint %s' % checkpoint]) + """Sends configuration commands to the remote device + """ + rc, out, err = self.exec_command('configure') + if rc != 0: + self._module.fail_json(msg='unable to enter configuration mode', output=err) - try: - self.configure(config) - except NetworkError: - self.load_checkpoint(checkpoint) - raise + for cmd in config: + rc, out, err = self.exec_command(cmd) + if rc != 0: + self._module.fail_json(msg=err) - try: - self.execute(['no checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['no checkpoint %s' % checkpoint]) + self.exec_command('end') - def save_config(self, **kwargs): - try: - self.execute(['copy running-config startup-config'], output='text') - except TypeError: - self.execute(['copy running-config startup-config']) - - def load_checkpoint(self, checkpoint): - try: - self.execute(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint], output='text') - except TypeError: - self.execute(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint]) - - -class Nxapi(NxapiConfigMixin): +class Nxapi: OUTPUT_TO_COMMAND_TYPE = { 'text': 'cli_show_ascii', @@ -83,20 +153,33 @@ class Nxapi(NxapiConfigMixin): 'config': 'cli_conf' } - def __init__(self): - self.url = None - self.url_args = ModuleStub(url_argument_spec(), self._error) + def __init__(self, module): + self._module = module self._nxapi_auth = None - self.default_output = 'json' - self._connected = False + self._device_configs = {} + + self._module.params['url_username'] = self._module.params['username'] + self._module.params['url_password'] = self._module.params['password'] + + host = self._module.params['host'] + port = self._module.params['port'] + + if self._module.params['use_ssl']: + proto = 'https' + port = port or 443 + else: + proto = 'http' + port = port or 80 + + self._url = '%s://%s:%s/ins' % (proto, host, port) def _error(self, msg, **kwargs): self._nxapi_auth = None if 'url' not in kwargs: - kwargs['url'] = self.url - raise NetworkError(msg, **kwargs) + kwargs['url'] = self._url + self._module.fail_json(msg=msg, **kwargs) - def _get_body(self, commands, output, version='1.0', chunk='0', sid=None): + def _request_builder(self, commands, output, version='1.0', chunk='0', sid=None): """Encodes a NXAPI JSON request message """ try: @@ -120,64 +203,41 @@ class Nxapi(NxapiConfigMixin): return dict(ins_api=msg) - def connect(self, params, **kwargs): - host = params['host'] - port = params['port'] - - # sets the module_utils/urls.py req parameters - self.url_args.params['url_username'] = params['username'] - self.url_args.params['url_password'] = params['password'] - self.url_args.params['validate_certs'] = params['validate_certs'] - self.url_args.params['timeout'] = params['timeout'] - - if params['use_ssl']: - proto = 'https' - port = port or 443 - else: - proto = 'http' - port = port or 80 - - self.url = '%s://%s:%s/ins' % (proto, host, port) - self._connected = True - - def disconnect(self, **kwargs): - self.url = None - self._nxapi_auth = None - self._connected = False - - ### Command methods ### - - def execute(self, commands, output=None, **kwargs): - commands = collections.deque(commands) - output = output or self.default_output - - # only 10 commands can be encoded in each request + def send_request(self, commands, output='text'): + # only 10 show commands can be encoded in each request # messages sent to the remote device - stack = list() - requests = list() + if output != 'config': + commands = collections.deque(commands) + stack = list() + requests = list() - while commands: - stack.append(commands.popleft()) - if len(stack) == 10: - body = self._get_body(stack, output) - data = self._jsonify(body) + while commands: + stack.append(commands.popleft()) + if len(stack) == 10: + body = self._request_builder(stack, output) + data = self._module.jsonify(body) + requests.append(data) + stack = list() + + if stack: + body = self._request_builder(stack, output) + data = self._module.jsonify(body) requests.append(data) - stack = list() - if stack: - body = self._get_body(stack, output) - data = self._jsonify(body) - requests.append(data) + else: + requests = commands headers = {'Content-Type': 'application/json'} result = list() - timeout = self.url_args.params['timeout'] + timeout = self._module.params['timeout'] or 10 + for req in requests: if self._nxapi_auth: headers['Cookie'] = self._nxapi_auth response, headers = fetch_url( - self.url_args, self.url, data=data, headers=headers, timeout=timeout, method='POST' + self._module, self._url, data=data, headers=headers, + timeout=timeout, method='POST' ) self._nxapi_auth = headers.get('set-cookie') @@ -185,9 +245,9 @@ class Nxapi(NxapiConfigMixin): self._error(**headers) try: - response = json.loads(response.read()) + response = self._module.from_json(response.read()) except ValueError: - raise NetworkError(msg='unable to load response from device') + self._module.fail_json(msg='unable to parse response') output = response['ins_api']['outputs']['output'] for item in to_list(output): @@ -198,115 +258,96 @@ class Nxapi(NxapiConfigMixin): return result - def run_commands(self, commands, **kwargs): + + def get_config(self, flags=[]): + """Retrieves the current config from the device or cache + """ + cmd = 'show running-config ' + cmd += ' '.join(flags) + cmd = cmd.strip() + + try: + return self._device_configs[cmd] + except KeyError: + out = self.send_request(cmd) + cfg = str(out['result'][0]['output']).strip() + self._device_configs[cmd] = cfg + return cfg + + + def run_commands(self, commands, check_rc=True): + """Run list of commands on remote device and return results + """ output = None - cmds = list() + queue = list() responses = list() - for cmd in commands: - if output and output != cmd.output: - responses.extend(self.execute(cmds, output=output)) - cmds = list() + _send = lambda commands, output: self.send_request(commands, output) - output = cmd.output - cmds.append(str(cmd)) + for item in to_list(commands): + if is_json(item['command']): + item['command'] = str(item['command']).split('|')[0] + item['output'] = 'json' - if cmds: - responses.extend(self.execute(cmds, output=output)) + if all((output == 'json', item['output'] == 'text')) or all((output =='text', item['output'] == 'json')): + responses.extend(_send(queue, output)) + queue = list() + + output = item['output'] or 'json' + queue.append(item['command']) + + if queue: + responses.extend(_send(queue, output)) return responses - - ### Config methods ### - - def configure(self, commands): - commands = to_list(commands) - return self.execute(commands, output='config') - - def _jsonify(self, data): - for encoding in ("utf-8", "latin-1"): - try: - return json.dumps(data, encoding=encoding) - # Old systems using old simplejson module does not support encoding keyword. - except TypeError: - try: - new_data = json_dict_bytes_to_unicode(data, encoding=encoding) - except UnicodeDecodeError: - continue - return json.dumps(new_data) - except UnicodeDecodeError: - continue - self._error(msg='Invalid unicode encoding encountered') - -Nxapi = register_transport('nxapi')(Nxapi) + def load_config(self, config): + """Sends the ordered set of commands to the device + """ + cmds = ['configure terminal'] + cmds.extend(commands) + self.send_request(commands, output='config') -class Cli(NxapiConfigMixin, CliBase): +is_json = lambda x: str(x).endswith('| json') +is_text = lambda x: not is_json - CLI_PROMPTS_RE = [ - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'), - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$') - ] +def is_nxapi(module): + transport = module.params['transport'] + provider_transport = (module.params['provider'] or {}).get('transport') + return 'nxapi' in (transport, provider_transport) - CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"^% \w+", re.M), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), - re.compile(r"syntax error"), - re.compile(r"unknown command") - ] +def to_command(module, commands): + if is_nxapi(module): + default_output = 'json' + else: + default_output = 'text' - NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) + transform = ComplexList(dict( + command=dict(key=True), + output=dict(default=default_output), + prompt=dict(), + response=dict() + ), module) - def connect(self, params, **kwargs): - super(Cli, self).connect(params, kickstart=False, **kwargs) - self.shell.send('terminal length 0') + commands = transform(to_list(commands)) - ### Command methods ### + for index, item in enumerate(commands): + if is_json(item['command']): + item['output'] = 'json' + elif is_text(item['command']): + item['output'] = 'text' - def run_commands(self, commands): - cmds = list(prepare_commands(commands)) - responses = self.execute(cmds) - for index, cmd in enumerate(commands): - raw = cmd.args.get('raw') or False - if cmd.output == 'json' and not raw: - try: - responses[index] = json.loads(responses[index]) - except ValueError: - raise NetworkError( - msg='unable to load response from device', - response=responses[index], command=str(cmd) - ) - return responses +def get_config(module, flags=[]): + conn = get_connection(module) + return conn.get_config(flags) - ### Config methods ### +def run_commands(module, commands, check_rc=True): + conn = get_connection(module) + to_command(module, commands) + return conn.run_commands(commands) - def configure(self, commands, **kwargs): - commands = prepare_config(commands) - responses = self.execute(commands) - responses.pop(0) - return responses +def load_config(module, config): + conn = get_connection(module) + return conn.load_config(config) -Cli = register_transport('cli', default=True)(Cli) - - -def prepare_config(commands): - prepared = ['config'] - prepared.extend(to_list(commands)) - prepared.append('end') - return prepared - - -def prepare_commands(commands): - jsonify = lambda x: '%s | json' % x - for cmd in to_list(commands): - if cmd.output == 'json': - cmd.command_string = jsonify(cmd) - if cmd.command.endswith('| json'): - cmd.output = 'json' - yield cmd diff --git a/lib/ansible/module_utils/nxos_cli.py b/lib/ansible/module_utils/nxos_cli.py deleted file mode 100644 index 65623b6abe..0000000000 --- a/lib/ansible/module_utils/nxos_cli.py +++ /dev/null @@ -1,157 +0,0 @@ -# -# This code is part of Ansible, but is an independent component. -# -# This particular file snippet, and this file snippet only, is BSD licensed. -# Modules you write using this snippet, which is embedded dynamically by Ansible -# still belong to the author of the module, and may assign their own license -# to the complete work. -# -# (c) 2017 Red Hat, Inc. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -import re - -from ansible.module_utils.shell import CliBase -from ansible.module_utils.basic import env_fallback, get_exception -from ansible.module_utils.network_common import to_list -from ansible.module_utils.netcli import Command -from ansible.module_utils.six import iteritems -from ansible.module_utils.network import NetworkError - -_DEVICE_CONFIGS = {} -_DEVICE_CONNECTION = None - -nxos_cli_argument_spec = { - 'host': dict(), - 'port': dict(type='int'), - - 'username': dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])), - 'password': dict(fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD']), no_log=True), - - 'authorize': dict(default=False, fallback=(env_fallback, ['ANSIBLE_NET_AUTHORIZE']), type='bool'), - 'auth_pass': dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_AUTH_PASS'])), - - 'timeout': dict(type='int', default=10), - - 'provider': dict(type='dict'), - - # deprecated in Ansible 2.3 - 'transport': dict(), -} - -def check_args(module, warnings): - provider = module.params['provider'] or {} - for key in ('host', 'username', 'password'): - if not module.params[key] and not provider.get(key): - module.fail_json(msg='missing required argument %s' % key) - -class Cli(CliBase): - - CLI_PROMPTS_RE = [ - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'), - re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$') - ] - - CLI_ERRORS_RE = [ - re.compile(r"% ?Error"), - re.compile(r"^% \w+", re.M), - re.compile(r"% ?Bad secret"), - re.compile(r"invalid input", re.I), - re.compile(r"(?:incomplete|ambiguous) command", re.I), - re.compile(r"connection timed out", re.I), - re.compile(r"[^\r\n]+ not found", re.I), - re.compile(r"'[^']' +returned error code: ?\d+"), - re.compile(r"syntax error"), - re.compile(r"unknown command") - ] - - NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I) - - def __init__(self, module): - self._module = module - super(Cli, self).__init__() - - provider = self._module.params.get('provider') or dict() - for key, value in iteritems(provider): - if key in nxos_cli_argument_spec: - if self._module.params.get(key) is None and value is not None: - self._module.params[key] = value - - try: - self.connect() - except NetworkError: - exc = get_exception() - self._module.fail_json(msg=str(exc)) - - if module.params['authorize']: - self.authorize() - - def connect(self): - super(Cli, self).connect(self._module.params, kickstart=False) - self.shell.send('terminal length 0') - - -def connection(module): - global _DEVICE_CONNECTION - if not _DEVICE_CONNECTION: - cli = Cli(module) - _DEVICE_CONNECTION = cli - return _DEVICE_CONNECTION - - -def get_config(module, flags=[]): - cmd = 'show running-config ' - cmd += ' '.join(flags) - cmd = cmd.strip() - - try: - return _DEVICE_CONFIGS[cmd] - except KeyError: - conn = connection(module) - out = conn.exec_command(cmd) - cfg = str(out).strip() - _DEVICE_CONFIGS[cmd] = cfg - return cfg - -def run_commands(module, commands, check_rc=True): - responses = list() - conn = connection(module) - for cmd in to_list(commands): - rc, out, err = conn.exec_command(cmd) - if check_rc and rc != 0: - module.fail_json(msg=err, rc=rc) - responses.append(out) - return responses - -def load_config(module, commands): - conn = connection(module) - rc, out, err = conn.exec_command('configure') - if rc != 0: - module.fail_json(msg='unable to enter configuration mode', err=err) - - for command in to_list(commands): - if command == 'end': - continue - rc, out, err = module.exec_command(command) - if rc != 0: - module.fail_json(msg=err, command=command, rc=rc) - - conn.exec_command('end') diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server.py b/lib/ansible/modules/network/nxos/nxos_aaa_server.py index 51ed607a25..ef0c685b61 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages AAA server global configuration. description: - Manages AAA server global configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -155,220 +154,19 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.six import iteritems - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -490,9 +288,16 @@ def main(): choices=['enabled', 'disabled', 'default']), state=dict(choices=['default', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server_type = module.params['server_type'] global_key = module.params['global_key'] encrypt_type = module.params['encrypt_type'] @@ -555,7 +360,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_aaa_server_info(server_type, module) if 'configure' in cmds: cmds.pop(0) @@ -565,6 +370,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -572,3 +378,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py index 47a8b3f004..ee2732564b 100644 --- a/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py +++ b/lib/ansible/modules/network/nxos/nxos_aaa_server_host.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages AAA server host-specific configuration. description: - Manages AAA server host-specific configuration. -extends_documentation_fragment: nxos author: Jason Edelman (@jedelman8) notes: - Changes to the AAA server host key (shared secret) are not idempotent. @@ -150,236 +149,11 @@ changed: type: boolean sample: true ''' - - -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - if isinstance(response[0], str): - body = [json.loads(response[0])] - else: - body = response - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): @@ -387,11 +161,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -495,9 +268,16 @@ def main(): tacacs_port=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server_type = module.params['server_type'] address = module.params['address'] key = module.params['key'] @@ -565,7 +345,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_aaa_host_info(module, server_type, address) results = {} @@ -573,6 +353,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -580,3 +361,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_acl.py b/lib/ansible/modules/network/nxos/nxos_acl.py index cf2dc9a7fb..1ac359241c 100644 --- a/lib/ansible/modules/network/nxos/nxos_acl.py +++ b/lib/ansible/modules/network/nxos/nxos_acl.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages access list entries for ACLs. description: - Manages access list entries for ACLs. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -241,227 +240,21 @@ changed: type: boolean sample: true ''' - -import collections -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0]: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -621,24 +414,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( seq=dict(required=False, type='str'), @@ -685,9 +460,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] action = module.params['action'] remark = module.params['remark'] @@ -797,7 +579,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True new_existing_core, end_state, seqs = get_acl(module, name, seq) if 'configure' in cmds: @@ -806,6 +588,7 @@ def main(): results['proposed'] = proposed results['existing'] = existing_core results['changed'] = changed + results['warnings'] = warnings results['updates'] = cmds results['end_state'] = end_state @@ -814,3 +597,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_acl_interface.py b/lib/ansible/modules/network/nxos/nxos_acl_interface.py index f5219aa06d..7c74d2eaad 100644 --- a/lib/ansible/modules/network/nxos/nxos_acl_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_acl_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages applying ACLs to interfaces. description: - Manages applying ACLs to interfaces. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -99,216 +98,11 @@ changed: type: boolean sample: true ''' - -import collections -import json - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0] or 'summary' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): @@ -316,11 +110,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'summary' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -446,24 +239,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( name=dict(required=False, type='str'), @@ -475,9 +250,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] name = module.params['name'] interface = module.params['interface'].lower() @@ -517,7 +299,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state_acls = get_acl_interface(module, name) interfaces_acls, this_dir_acl_intf = other_existing_acl( @@ -533,6 +315,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state results['acl_applied_to'] = end_state_acls @@ -541,3 +324,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp.py b/lib/ansible/modules/network/nxos/nxos_bgp.py index 8c4cc10d2a..62362ef8c1 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp.py @@ -30,7 +30,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP ASN configuration when C(vrf=default) or the whole VRF instance within the BGP process when @@ -361,156 +360,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] @@ -902,11 +756,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['timer_bgp_hold', 'timer_bgp_keepalive']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ "asn", @@ -1010,3 +871,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_af.py index 08f603f519..e804140084 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_af.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_af.py @@ -28,7 +28,6 @@ short_description: Manages BGP Address-family configuration. description: - Manages BGP Address-family configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP ASN configuration - Default, where supported, restores params default value. @@ -300,157 +299,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] BOOL_PARAMS = [ @@ -992,13 +845,20 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[DAMPENING_PARAMS, ['distance_ibgp', 'distance_ebgp', 'distance_local']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if module.params['dampening_routemap']: for param in DAMPENING_PARAMS: @@ -1108,3 +968,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py index 960e2d966f..7446559dab 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor.py @@ -28,7 +28,6 @@ short_description: Manages BGP neighbors configurations. description: - Manages BGP neighbors configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP neighbor configuration. - Default, where supported, restores params default value. @@ -245,156 +244,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] @@ -682,11 +536,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['timer_bgp_hold', 'timer_bgp_keepalive']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if module.params['pwd_type'] == 'default': module.params['pwd_type'] = '0' @@ -767,3 +628,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py index ebb886760a..f18a3f9daa 100644 --- a/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py +++ b/lib/ansible/modules/network/nxos/nxos_bgp_neighbor_af.py @@ -28,7 +28,6 @@ short_description: Manages BGP address-family's neighbors configuration. description: - Manages BGP address-family's neighbors configurations on NX-OS switches. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) removes the whole BGP address-family's neighbor configuration. @@ -322,156 +321,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig WARNINGS = [] BOOL_PARAMS = [ @@ -1004,11 +858,18 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['advertise_map_exist', 'advertise_map_non_exist']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] if ((module.params['max_prefix_interval'] or module.params['max_prefix_warning'] or @@ -1120,3 +981,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_command.py b/lib/ansible/modules/network/nxos/nxos_command.py index b90034a09e..5daeb442fb 100644 --- a/lib/ansible/modules/network/nxos/nxos_command.py +++ b/lib/ansible/modules/network/nxos/nxos_command.py @@ -16,9 +16,11 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -31,7 +33,6 @@ description: read from the device. This module includes an argument that will cause the module to wait for a specific condition before returning or timing out if the condition is not met. -extends_documentation_fragment: nxos options: commands: description: @@ -152,37 +153,53 @@ failed_conditions: type: list sample: ['...', '...'] """ -import ansible.module_utils.nxos +import time -from ansible.module_utils.basic import get_exception -from ansible.module_utils.network import NetworkModule, NetworkError -from ansible.module_utils.netcli import CommandRunner -from ansible.module_utils.netcli import FailedConditionsError -from ansible.module_utils.netcli import FailedConditionalError -from ansible.module_utils.netcli import AddCommandError, AddConditionError - -VALID_KEYS = ['command', 'output', 'prompt', 'response'] +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.pycompat24 import get_exception +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import string_types +from ansible.module_utils.netcli import Conditional +from ansible.module_utils.network_common import ComplexList +from ansible.module_utils.nxos import nxos_argument_spec, check_args def to_lines(stdout): + lines = list() for item in stdout: if isinstance(item, basestring): item = str(item).split('\n') - yield item + lines.append(item) + return lines -def parse_commands(module): - for cmd in module.params['commands']: - if isinstance(cmd, basestring): - cmd = dict(command=cmd, output=None) - elif 'command' not in cmd: - module.fail_json(msg='command keyword argument is required') - elif cmd.get('output') not in [None, 'text', 'json']: - module.fail_json(msg='invalid output specified for command') - elif not set(cmd.keys()).issubset(VALID_KEYS): - module.fail_json(msg='unknown keyword specified') - yield cmd +def parse_commands(module, warnings): + transform = ComplexList(dict( + command=dict(key=True), + output=dict(), + prompt=dict(), + response=dict() + ), module) + + commands = transform(module.params['commands']) + + for index, item in enumerate(commands): + if module.check_mode and not item['command'].startswith('show'): + warnings.append( + 'Only show commands are supported when using check_mode, not ' + 'executing %s' % item['command'] + ) + + return commands + +def to_cli(obj): + cmd = obj['command'] + if obj.get('output') == 'json': + cmd += ' | json' + return cmd def main(): - spec = dict( + """entry point for module execution + """ + argument_spec = dict( # { command: , output: , prompt: , response: } commands=dict(type='list', required=True), @@ -193,66 +210,56 @@ def main(): interval=dict(default=1, type='int') ) - module = NetworkModule(argument_spec=spec, + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - commands = list(parse_commands(module)) - conditionals = module.params['wait_for'] or list() + + result = {'changed': False} warnings = list() - - runner = CommandRunner(module) - - for cmd in commands: - if module.check_mode and not cmd['command'].startswith('show'): - warnings.append('only show commands are supported when using ' - 'check mode, not executing `%s`' % cmd['command']) - else: - if cmd['command'].startswith('conf'): - module.fail_json(msg='nxos_command does not support running ' - 'config mode commands. Please use ' - 'nxos_config instead') - try: - runner.add_command(**cmd) - except AddCommandError: - exc = get_exception() - warnings.append('duplicate command detected: %s' % cmd) - - try: - for item in conditionals: - runner.add_conditional(item) - except AddConditionError: - exc = get_exception() - module.fail_json(msg=str(exc), condition=exc.condition) - - runner.retries = module.params['retries'] - runner.interval = module.params['interval'] - runner.match = module.params['match'] - - try: - runner.run() - except FailedConditionsError: - exc = get_exception() - module.fail_json(msg=str(exc), failed_conditions=exc.failed_conditions) - except FailedConditionalError: - exc = get_exception() - module.fail_json(msg=str(exc), failed_conditional=exc.failed_conditional) - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - result = dict(changed=False) - - result['stdout'] = list() - for cmd in commands: - try: - output = runner.get_command(cmd['command'], cmd.get('output')) - except ValueError: - output = 'command not executed due to check_mode, see warnings' - result['stdout'].append(output) - + check_args(module, warnings) + commands = parse_commands(module, warnings) result['warnings'] = warnings - result['stdout_lines'] = list(to_lines(result['stdout'])) + + wait_for = module.params['wait_for'] or list() + + try: + conditionals = [Conditional(c) for c in wait_for] + except AttributeError: + exc = get_exception() + module.fail_json(msg=str(exc)) + + retries = module.params['retries'] + interval = module.params['interval'] + match = module.params['match'] + + while retries > 0: + responses = run_commands(module, commands) + + for item in list(conditionals): + if item(responses): + if match == 'any': + conditionals = list() + break + conditionals.remove(item) + + if not conditionals: + break + + time.sleep(interval) + retries -= 1 + + if conditionals: + failed_conditions = [item.raw for item in conditionals] + msg = 'One or more conditional statements have not be satisfied' + module.fail_json(msg=msg, failed_conditions=failed_conditions) + + result.update({ + 'stdout': responses, + 'stdout_lines': to_lines(responses) + }) module.exit_json(**result) diff --git a/lib/ansible/modules/network/nxos/nxos_config.py b/lib/ansible/modules/network/nxos/nxos_config.py index 2355ec37d8..fbb3ed7751 100644 --- a/lib/ansible/modules/network/nxos/nxos_config.py +++ b/lib/ansible/modules/network/nxos/nxos_config.py @@ -16,9 +16,11 @@ # along with Ansible. If not, see . # -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -32,7 +34,6 @@ description: an implementation for working with NXOS configuration sections in a deterministic way. This module works with either CLI or NXAPI transports. -extends_documentation_fragment: nxos options: lines: description: @@ -212,18 +213,28 @@ backup_path: type: path sample: /playbooks/ansible/backup/nxos_config.2016-07-16@22:28:34 """ - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.network import NetworkModule, NetworkError +from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.netcfg import NetworkConfig, dumps +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.nxos import check_args as nxos_check_args def check_args(module, warnings): + nxos_check_args(module, warnings) if module.params['force']: warnings.append('The force argument is deprecated, please use ' 'match=none instead. This argument will be ' 'removed in the future') +def get_running_config(module): + contents = module.params['config'] + if not contents: + flags = [] + if module.params['defaults']: + flags.append('all') + contents = get_config(module, flags=flags) + return NetworkConfig(indent=1, contents=contents) + def get_candidate(module): candidate = NetworkConfig(indent=2) if module.params['src']: @@ -233,13 +244,6 @@ def get_candidate(module): candidate.add(module.params['lines'], parents=parents) return candidate -def get_config(module): - contents = module.params['config'] - if not contents: - defaults = module.params['defaults'] - contents = module.config.get_config(include_defaults=defaults) - return NetworkConfig(indent=2, contents=contents) - def run(module, result): match = module.params['match'] replace = module.params['replace'] @@ -247,10 +251,9 @@ def run(module, result): candidate = get_candidate(module) if match != 'none': - config = get_config(module) + config = get_running_config(module) path = module.params['parents'] - configobjs = candidate.difference(config, path=path, match=match, - replace=replace) + configobjs = candidate.difference(config, match=match, replace=replace, path=path) else: configobjs = candidate.items @@ -264,22 +267,17 @@ def run(module, result): if module.params['after']: commands.extend(module.params['after']) - result['updates'] = commands + result['commands'] = commands + result['updates'] = commands if not module.check_mode: - module.config.load_config(commands) + load_config(module, commands) result['changed'] = True - if module.params['save']: - if not module.check_mode: - module.config.save_config() - result['changed'] = True - def main(): """ main entry point for module execution """ - argument_spec = dict( src=dict(type='path'), @@ -303,14 +301,15 @@ def main(): save=dict(type='bool', default=False), ) + argument_spec.update(nxos_argument_spec) + mutually_exclusive = [('lines', 'src')] required_if = [('match', 'strict', ['lines']), ('match', 'exact', ['lines']), ('replace', 'block', ['lines'])] - module = NetworkModule(argument_spec=argument_spec, - connect_on_load=False, + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=mutually_exclusive, required_if=required_if, supports_check_mode=True) @@ -326,11 +325,13 @@ def main(): if module.params['backup']: result['__backup__'] = module.config.get_config() - try: + if any((module.params['src'], module.params['lines'])): run(module, result) - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) + + if module.params['save']: + if not module.check_mode: + run_commands(module, ['copy running-config startup-config']) + result['changed'] = True module.exit_json(**result) diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_global.py b/lib/ansible/modules/network/nxos/nxos_evpn_global.py index 20f6f8784e..befbb64c35 100644 --- a/lib/ansible/modules/network/nxos/nxos_evpn_global.py +++ b/lib/ansible/modules/network/nxos/nxos_evpn_global.py @@ -28,7 +28,6 @@ short_description: Handles the EVPN control plane for VXLAN. description: - Handles the EVPN control plane for VXLAN. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: nv_overlay_evpn: description: @@ -73,156 +72,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'nv_overlay_evpn': 'nv overlay evpn', @@ -286,9 +140,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + existing = invoke('get_existing', module) end_state = existing proposed = dict(nv_overlay_evpn=module.params['nv_overlay_evpn']) @@ -314,8 +175,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py index 08c73d6911..a62f28fd3c 100644 --- a/lib/ansible/modules/network/nxos/nxos_evpn_vni.py +++ b/lib/ansible/modules/network/nxos/nxos_evpn_vni.py @@ -29,7 +29,6 @@ description: - Manages Cisco Ethernet Virtual Private Network (EVPN) VXLAN Network Identifier (VNI) configurations of a Nexus device. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - default, where supported, restores params default value. - RD override is not permitted. You should set it to the default values @@ -127,156 +126,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'vni': 'vni', @@ -420,9 +274,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ 'vni', @@ -490,3 +351,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_facts.py b/lib/ansible/modules/network/nxos/nxos_facts.py index b3fd2a7fd9..4e1d4f1ebb 100644 --- a/lib/ansible/modules/network/nxos/nxos_facts.py +++ b/lib/ansible/modules/network/nxos/nxos_facts.py @@ -176,31 +176,24 @@ vlan_list: """ import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcli import CommandRunner, AddCommandError -from ansible.module_utils.network import NetworkModule, NetworkError +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.network_common import exec_command from ansible.module_utils.six import iteritems -def add_command(runner, command, output=None): - try: - runner.add_command(command, output) - except AddCommandError: - # AddCommandError is raised for any issue adding a command to - # the runner. Silently ignore the exception in this case - pass - class FactsBase(object): - def __init__(self, module, runner): - self.module = module - self.runner = runner - self.facts = dict() - self.commands() + COMMANDS = frozenset() - def commands(self): - raise NotImplementedError + def __init__(self, module): + self.module = module + self.facts = dict() + self.responses = None + + def populate(self): + self.responses = run_commands(self.module, list(self.COMMANDS)) def transform_dict(self, data, keymap): transform = dict() @@ -224,33 +217,36 @@ class Default(FactsBase): ('host_name', 'hostname') ]) - def commands(self): - add_command(self.runner, 'show version', output='json') + COMMANDS = ['show version | json'] def populate(self): - data = self.runner.get_command('show version', output='json') + super(Default, self).populate() + data = self.responses[0] self.facts.update(self.transform_dict(data, self.VERSION_MAP)) class Config(FactsBase): - def commands(self): - add_command(self.runner, 'show running-config') + COMMANDS = ['show running-config'] def populate(self): - self.facts['config'] = self.runner.get_command('show running-config') + super(Config, self).populate() + data = self.responses[0] + self.facts['config'] = data class Hardware(FactsBase): - def commands(self): - add_command(self.runner, 'dir', output='text') - add_command(self.runner, 'show system resources', output='json') + COMMANDS = [ + 'dir', + 'show system resources | json' + ] def populate(self): - data = self.runner.get_command('dir', 'text') + super(Hardware, self).populate() + data = self.responses[0] self.facts['filesystems'] = self.parse_filesystems(data) - data = self.runner.get_command('show system resources', output='json') + data = self.responses[1] self.facts['memtotal_mb'] = int(data['memory_usage_total']) / 1024 self.facts['memfree_mb'] = int(data['memory_usage_free']) / 1024 @@ -282,38 +278,21 @@ class Interfaces(FactsBase): ('prefix', 'subnet') ]) - def commands(self): - add_command(self.runner, 'show interface', output='json') - - try: - self.module.cli('show ipv6 interface', 'json') - add_command(self.runner, 'show ipv6 interface', output='json') - self.ipv6 = True - except NetworkError: - self.ipv6 = False - - try: - self.module.cli(['show lldp neighbors']) - add_command(self.runner, 'show lldp neighbors', output='json') - self.lldp_enabled = True - except NetworkError: - self.lldp_enabled = False - def populate(self): self.facts['all_ipv4_addresses'] = list() self.facts['all_ipv6_addresses'] = list() - data = self.runner.get_command('show interface', 'json') + data = run_commands(self.module, ['show interface | json'])[0] self.facts['interfaces'] = self.populate_interfaces(data) - if self.ipv6: - data = self.runner.get_command('show ipv6 interface', 'json') - if data: - self.parse_ipv6_interfaces(data) + rc, out, err = exec_command(self.module, 'show ipv6 interface | json') + if rc == 0: + if out: + self.parse_ipv6_interfaces(out) - if self.lldp_enabled: - data = self.runner.get_command('show lldp neighbors', 'json') - self.facts['neighbors'] = self.populate_neighbors(data) + rc, out, err = exec_command(self.module, 'show lldp neighbors') + if rc == 0: + self.facts['neighbors'] = self.populate_neighbors(out) def populate_interfaces(self, data): interfaces = dict() @@ -390,27 +369,30 @@ class Legacy(FactsBase): ('total_capa', 'total_capacity') ]) - def commands(self): - add_command(self.runner, 'show version', output='json') - add_command(self.runner, 'show module', output='json') - add_command(self.runner, 'show environment', output='json') - add_command(self.runner, 'show interface', output='json') - add_command(self.runner, 'show vlan brief', output='json') + COMMANDS = [ + 'show version | json', + 'show module | json', + 'show environment | json', + 'show interface | json', + 'show vlan brief | json' + ] + def populate(self): - data = self.runner.get_command('show version', 'json') + super(Legacy, self).populate() + data = self.responses[0] self.facts.update(self.transform_dict(data, self.VERSION_MAP)) - data = self.runner.get_command('show interface', 'json') + data = self.responses[3] self.facts['_interfaces_list'] = self.parse_interfaces(data) - data = self.runner.get_command('show vlan brief', 'json') + data = self.responses[4] self.facts['_vlan_list'] = self.parse_vlans(data) - data = self.runner.get_command('show module', 'json') + data = self.responses[1] self.facts['_module'] = self.parse_module(data) - data = self.runner.get_command('show environment', 'json') + data = self.responses[2] self.facts['_fan_info'] = self.parse_fan_info(data) self.facts['_power_supply_info'] = self.parse_power_supply_info(data) @@ -463,7 +445,12 @@ def main(): gather_subset=dict(default=['!config'], type='list') ) - module = NetworkModule(argument_spec=spec, supports_check_mode=True) + spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=spec, supports_check_mode=True) + + warnings = list() + check_args(module, warnings) gather_subset = module.params['gather_subset'] @@ -501,25 +488,13 @@ def main(): facts = dict() facts['gather_subset'] = list(runable_subsets) - runner = CommandRunner(module) - instances = list() for key in runable_subsets: - instances.append(FACT_SUBSETS[key](module, runner)) + instances.append(FACT_SUBSETS[key](module)) - try: - runner.run() - except NetworkError: - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - try: - for inst in instances: - inst.populate() - facts.update(inst.facts) - except Exception: - raise - module.exit_json(out=module.from_json(runner.items)) + for inst in instances: + inst.populate() + facts.update(inst.facts) ansible_facts = dict() for key, value in iteritems(facts): @@ -530,7 +505,7 @@ def main(): key = 'ansible_net_%s' % key ansible_facts[key] = value - module.exit_json(ansible_facts=ansible_facts) + module.exit_json(ansible_facts=ansible_facts, warnings=warnings) if __name__ == '__main__': diff --git a/lib/ansible/modules/network/nxos/nxos_feature.py b/lib/ansible/modules/network/nxos/nxos_feature.py index 3e23d22d08..336ee7085d 100644 --- a/lib/ansible/modules/network/nxos/nxos_feature.py +++ b/lib/ansible/modules/network/nxos/nxos_feature.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manage features in NX-OS switches. description: - Offers ability to enable and disable features in NX-OS. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,244 +96,11 @@ feature: type: string sample: "vpc" ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'xml' in response[0]: - body = [] - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - command += ' | json' - cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) - elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - - return body - +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def apply_key_map(key_map, table): new_dict = {} @@ -354,7 +120,8 @@ def get_available_features(feature, module): feature_regex = '(?P\S+)\s+\d+\s+(?P.*)' command = 'show feature' - body = execute_show_command(command, module, command_type='cli_show_ascii') + command = {'command': command, 'output': 'text'} + body = run_commands(module, [command]) split_body = body[0].splitlines() for line in split_body: @@ -451,9 +218,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + feature = validate_feature(module) state = module.params['state'].lower() @@ -477,7 +251,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True updated_features = get_available_features(feature, module) existstate = updated_features[feature] @@ -491,6 +265,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['feature'] = module.params['feature'] module.exit_json(**results) @@ -498,3 +273,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_file_copy.py b/lib/ansible/modules/network/nxos/nxos_file_copy.py index 8f241658f0..891f32e123 100644 --- a/lib/ansible/modules/network/nxos/nxos_file_copy.py +++ b/lib/ansible/modules/network/nxos/nxos_file_copy.py @@ -31,7 +31,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - The feature must be enabled with feature scp-server. - If the file is already present (md5 sums match), no transfer will @@ -82,205 +81,29 @@ remote_file: type: string sample: '/path/to/remote/file' ''' - - import os -from scp import SCPClient -import paramiko +import re import time -# COMMON CODE FOR MIGRATION -import re +import paramiko -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError +from ansible.module_utils.nxos import run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule try: - from ansible.module_utils.nxos import get_module + from scp import SCPClient + HAS_SCP = True except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - + HAS_SCP = False def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': cmds = [command] - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -372,8 +195,20 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + if not HAS_SCP: + module.fail_json( + msg='library scp is required but does not appear to be ' + 'installed. It can be installed using `pip install scp`' + ) + + warnings = list() + check_args(module, warnings) local_file = module.params['local_file'] remote_file = module.params['remote_file'] @@ -409,8 +244,10 @@ def main(): transfer_status=transfer_status, local_file=local_file, remote_file=remote_file, + warnings=warnings, file_system=file_system) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_gir.py b/lib/ansible/modules/network/nxos/nxos_gir.py index cb22ae12d4..5d091a70e5 100644 --- a/lib/ansible/modules/network/nxos/nxos_gir.py +++ b/lib/ansible/modules/network/nxos/nxos_gir.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Trigger a graceful removal or insertion (GIR) of the switch. description: - Trigger a graceful removal or insertion (GIR) of the switch. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -161,220 +160,22 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_system_mode(module): command = 'show system mode' body = execute_show_command(command, module)[0] @@ -468,7 +269,10 @@ def main(): state=dict(choices=['absent', 'present', 'default'], default='present', required=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[[ 'system_mode_maintenance', 'system_mode_maintenance_dont_generate_profile', @@ -485,6 +289,10 @@ def main(): ]], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] mode = get_system_mode(module) commands = get_commands(module, state, mode) @@ -493,7 +301,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True result = {} @@ -504,8 +312,11 @@ def main(): result['final_system_mode'] = final_system_mode result['updates'] = commands + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py b/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py index 5d7751141b..fa5328f9ce 100644 --- a/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py +++ b/lib/ansible/modules/network/nxos/nxos_gir_profile_management.py @@ -29,7 +29,6 @@ description: - Manage a maintenance-mode or normal-mode profile with configuration commands that can be applied during graceful removal or graceful insertion. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -117,159 +116,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def get_existing(module): @@ -315,24 +166,6 @@ def invoke(name, *args, **kwargs): return func(*args, **kwargs) -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( commands=dict(required=False, type='list'), @@ -342,9 +175,16 @@ def main(): include_defaults=dict(default=False), config=dict() ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] commands = module.params['commands'] or [] @@ -363,7 +203,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = invoke('get_existing', module) @@ -376,8 +216,11 @@ def main(): result['proposed'] = commands result['updates'] = cmds + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_hsrp.py b/lib/ansible/modules/network/nxos/nxos_hsrp.py index c5f766ca7a..5854be331c 100644 --- a/lib/ansible/modules/network/nxos/nxos_hsrp.py +++ b/lib/ansible/modules/network/nxos/nxos_hsrp.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages HSRP configuration on NX-OS switches. description: - Manages HSRP configuration on NX-OS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -143,239 +142,21 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -619,9 +400,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'].lower() group = module.params['group'] version = module.params['version'] @@ -699,7 +487,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - body = execute_config_command(commands, module) + load_config(module, commands) if transport == 'cli': validate_config(body, vip, module) changed = True @@ -713,9 +501,11 @@ def main(): results['end_state'] = end_state results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp.py b/lib/ansible/modules/network/nxos/nxos_igmp.py index 7cc36bb392..1262a649e3 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages IGMP global configuration. description: - Manages IGMP global configuration configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -110,159 +109,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'flush_routes': 'ip igmp flush-routes', @@ -343,9 +194,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] restart = module.params['restart'] @@ -392,8 +250,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py index 1432c4d47f..65c3eacf27 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages IGMP interface configuration. description: - Manages IGMP interface configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -233,225 +232,21 @@ changed: sample: true ''' -import json -import collections +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -712,24 +507,6 @@ def config_remove_oif(existing, existing_oif_prefix_source): return commands -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def main(): argument_spec = dict( interface=dict(required=True, type='str'), @@ -755,9 +532,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'] oif_prefix = module.params['oif_prefix'] @@ -891,7 +675,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = get_igmp_interface(module, interface) if 'configure' in cmds: @@ -901,6 +685,7 @@ def main(): results['existing'] = existing_copy results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -908,3 +693,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py b/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py index f63b75f0ed..065369a50b 100644 --- a/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py +++ b/lib/ansible/modules/network/nxos/nxos_igmp_snooping.py @@ -30,7 +30,6 @@ description: author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - When C(state=default), params will be reset to a default state. - C(group_timeout) also accepts I(never) as an input. @@ -129,229 +128,23 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - if isinstance(response[0], str): - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response[0])] - else: - body = response - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -366,24 +159,6 @@ def flatten_list(command_lists): return flat_command_list -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_group_timeout(config): command = 'ip igmp snooping group-timeout' REGEX = re.compile(r'(?:{0}\s)(?P.*)$'.format(command), re.M) @@ -492,9 +267,16 @@ def main(): v3_report_supp=dict(required=False, type='bool'), state=dict(choices=['present', 'default'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + snooping = module.params['snooping'] link_local_grp_supp = module.params['link_local_grp_supp'] report_supp = module.params['report_supp'] @@ -539,7 +321,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_igmp_snooping(module) if 'configure' in cmds: cmds.pop(0) @@ -548,9 +330,11 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_install_os.py b/lib/ansible/modules/network/nxos/nxos_install_os.py index f0ba09be7c..59640dc8df 100644 --- a/lib/ansible/modules/network/nxos/nxos_install_os.py +++ b/lib/ansible/modules/network/nxos/nxos_install_os.py @@ -115,220 +115,23 @@ install_state: ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_boot_options(module): """Get current boot variables like system image and kickstart image. @@ -376,7 +179,7 @@ def set_boot_options(module, image_name, kickstart=None): else: commands.append( 'install all system %s kickstart %s' % (image_name, kickstart)) - execute_config_command(commands, module) + load_config(module, commands) def main(): @@ -384,9 +187,16 @@ def main(): system_image_file=dict(required=True), kickstart_image_file=dict(required=False), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + system_image_file = module.params['system_image_file'] kickstart_image_file = module.params['kickstart_image_file'] @@ -413,8 +223,9 @@ def main(): else: install_state = current_boot_options - module.exit_json(changed=changed, install_state=install_state) + module.exit_json(changed=changed, install_state=install_state, warnings=warnings) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_interface.py b/lib/ansible/modules/network/nxos/nxos_interface.py index fafbae89ea..93532df3fc 100644 --- a/lib/ansible/modules/network/nxos/nxos_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_interface.py @@ -162,157 +162,12 @@ changed: sample: true ''' -import json - -# COMMON CODE FOR MIGRATION - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE def is_default_interface(interface, module): @@ -710,95 +565,23 @@ def smart_existing(module, intf_type, normalized_interface): return existing, is_default -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + cmds = [{'command': command, 'output': 'json'}] + body = run_commands(module, cmds) return body def execute_modified_show_for_cli_text(command, module): cmds = [command] if module.params['transport'] == 'cli': - response = execute_show(cmds, module) + body = run_commands(module, cmds) else: - response = execute_show(cmds, module, command_type='cli_show_ascii') + body = run_commands(module, cmds) body = response return body @@ -840,10 +623,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['interface', 'interface_type']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + interface = module.params['interface'] interface_type = module.params['interface_type'] admin_state = module.params['admin_state'] @@ -937,7 +726,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True if module.params['interface']: if delta.get('mode'): # or delta.get('admin_state'): @@ -948,7 +737,7 @@ def main(): c1 = 'interface {0}'.format(normalized_interface) c2 = get_admin_state(delta, normalized_interface, admin_state) cmds2 = [c1, c2] - execute_config_command(cmds2, module) + load_config(module, cmds2) cmds.extend(cmds2) end_state, is_default = smart_existing(module, intf_type, normalized_interface) @@ -962,9 +751,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py index 36fbf5cd28..61f22b5363 100644 --- a/lib/ansible/modules/network/nxos/nxos_interface_ospf.py +++ b/lib/ansible/modules/network/nxos/nxos_interface_ospf.py @@ -28,7 +28,6 @@ short_description: Manages configuration of an OSPF interface instance. description: - Manages configuration of an OSPF interface instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default, where supported, restores params default value. - To remove an existing authentication configuration you should use @@ -167,156 +166,11 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re - -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = [ 'passive_interface', @@ -597,7 +451,10 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['message_digest_key_id', 'message_digest_algorithm_type', 'message_digest_encryption_type', @@ -607,6 +464,9 @@ def main(): if not module.params['interface'].startswith('loopback'): module.params['interface'] = module.params['interface'].capitalize() + warnings = list() + check_args(module, warnings) + for param in ['message_digest_encryption_type', 'message_digest_algorithm_type', 'message_digest_password']: @@ -674,8 +534,11 @@ def main(): result['existing'] = existing result['proposed'] = proposed_args + result['warnings'] = warnings + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ip_interface.py b/lib/ansible/modules/network/nxos/nxos_ip_interface.py index e2ae39955c..e36a51aed2 100644 --- a/lib/ansible/modules/network/nxos/nxos_ip_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_ip_interface.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages L3 attributes for IPv4 and IPv6 interfaces. description: - Manages Layer 3 attributes for IPv4 and IPv6 interfaces. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -111,242 +110,21 @@ changed: sample: true ''' -import json -import collections +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, we assume if '^' is found in response, - it is an invalid command. - """ - if 'xml' in response[0]: - body = [] - elif '^' in response[0] or 'show run' in response[0] or response[0] == '\n': - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -640,9 +418,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + addr = module.params['addr'] version = module.params['version'] mask = module.params['mask'] @@ -702,7 +487,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state, address_list = get_ip_interface(interface, version, module) @@ -715,9 +500,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_mtu.py b/lib/ansible/modules/network/nxos/nxos_mtu.py index 35b3303c36..2299e79134 100644 --- a/lib/ansible/modules/network/nxos/nxos_mtu.py +++ b/lib/ansible/modules/network/nxos/nxos_mtu.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages MTU settings on Nexus switch. description: - Manages MTU settings on Nexus switch. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -118,245 +117,19 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +from ansible.module_utils.nxos import load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -503,9 +276,15 @@ def main(): sysmtu=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, - required_together=[['mtu', 'interface']], - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + required_together=[['mtu', 'interface']], + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) interface = module.params['interface'] mtu = module.params['mtu'] @@ -576,7 +355,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) if interface: end_state = get_mtu(interface, module) else: @@ -590,9 +369,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp.py b/lib/ansible/modules/network/nxos/nxos_ntp.py index 721fc473f7..27285bf691 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages core NTP configuration. description: - Manages core NTP configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) options: @@ -125,243 +124,23 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -530,12 +309,19 @@ def main(): source_int=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[ ['server','peer'], ['source_addr','source_int']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + server = module.params['server'] or None peer = module.params['peer'] or None key_id = module.params['key_id'] @@ -616,7 +402,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_ntp_existing(address, peer_type, module)[0] if 'configure' in cmds: cmds.pop(0) @@ -626,6 +412,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state results['peer_server_list'] = peer_server_list @@ -635,3 +422,4 @@ def main(): from ansible.module_utils.basic import * if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp_auth.py b/lib/ansible/modules/network/nxos/nxos_ntp_auth.py index 4d094c49cd..43811c12d8 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp_auth.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp_auth.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages NTP authentication. description: - Manages NTP authentication. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -123,243 +122,23 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -503,9 +282,16 @@ def main(): authentication=dict(choices=['on', 'off']), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + key_id = module.params['key_id'] md5string = module.params['md5string'] auth_type = module.params['auth_type'] @@ -548,7 +334,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: try: - execute_config_command(cmds, module) + load_config(module, cmds) except ShellError: clie = get_exception() module.fail_json(msg=str(clie) + ": " + cmds) @@ -564,9 +350,11 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ntp_options.py b/lib/ansible/modules/network/nxos/nxos_ntp_options.py index 0bf1fb70f7..23be4f8c73 100644 --- a/lib/ansible/modules/network/nxos/nxos_ntp_options.py +++ b/lib/ansible/modules/network/nxos/nxos_ntp_options.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages NTP options. description: - Manages NTP options, e.g. authoritative server and logging. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -104,243 +103,24 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -442,10 +222,17 @@ def main(): logging=dict(required=False, type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['master', 'logging']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + master = module.params['master'] stratum = module.params['stratum'] logging = module.params['logging'] @@ -500,7 +287,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_ntp_options(module) if 'configure' in cmds: cmds.pop(0) @@ -510,6 +297,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -517,3 +305,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_nxapi.py b/lib/ansible/modules/network/nxos/nxos_nxapi.py index 9a3985a92f..5108b24d52 100644 --- a/lib/ansible/modules/network/nxos/nxos_nxapi.py +++ b/lib/ansible/modules/network/nxos/nxos_nxapi.py @@ -16,10 +16,11 @@ # along with Ansible. If not, see . # - -ANSIBLE_METADATA = {'status': ['preview'], - 'supported_by': 'core', - 'version': '1.0'} +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} DOCUMENTATION = """ --- @@ -32,7 +33,6 @@ description: NXAPI feature is absent from the configuration by default. Since this module manages the NXAPI feature it only supports the use of the C(Cli) transport. -extends_documentation_fragment: nxos options: http_port: description: @@ -84,15 +84,6 @@ options: default: no choices: ['yes', 'no'] aliases: ['enable_sandbox'] - config: - description: - - The C(config) argument provides an optional argument to - specify the device running-config to used as the basis for - configuring the remote system. The C(config) argument accepts - a string value that represents the device configuration. - required: false - default: null - version_added: "2.2" state: description: - The C(state) argument controls whether or not the NXAPI @@ -106,17 +97,9 @@ options: """ EXAMPLES = """ -# Note: examples below use the following provider dict to handle -# transport and authentication to the node. -vars: - cli: - host: "{{ inventory_hostname }}" - username: admin - password: admin - - name: Enable NXAPI access with default configuration nxos_nxapi: - provider: "{{ cli }}" + state: present - name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled nxos_nxapi: @@ -124,12 +107,10 @@ vars: https_port: 9443 https: yes enable_sandbox: no - provider: "{{ cli }}" - name: remove NXAPI configuration nxos_nxapi: state: absent - provider: "{{ cli }}" """ RETURN = """ @@ -142,189 +123,172 @@ updates: sample: ['no feature nxapi'] """ import re -import time -from ansible.module_utils.netcfg import NetworkConfig, dumps -from ansible.module_utils.nxos import NetworkModule, NetworkError -from ansible.module_utils.basic import get_exception +from functools import partial -PRIVATE_KEYS_RE = re.compile('__.+__') +from ansible.module_utils.nxos import run_commands, load_config +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.nxos import check_args as nxos_check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import NetworkConfig +from ansible.module_utils.six import iteritems -def invoke(name, *args, **kwargs): - func = globals().get(name) - if func: - return func(*args, **kwargs) +def check_args(module, warnings): + nxos_check_args(module, warnings) -def get_instance(module): - instance = dict(state='absent') - try: - resp = module.cli('show nxapi', 'json') - except NetworkError: - return instance + state = module.params['state'] - instance['state'] = 'present' + if state == 'started': + module.params['state'] = 'present' + warnings.append('state=started is deprecated and will be removed in a ' + 'a future release. Please use state=present instead') + elif state == 'stopped': + module.params['state'] = 'absent' + warnings.append('state=stopped is deprecated and will be removed in a ' + 'a future release. Please use state=absent instead') - instance['http'] = 'http_port' in resp[0] - instance['http_port'] = resp[0].get('http_port') or 80 + if module.params['transport'] == 'nxapi': + module.fail_json(msg='module not supported over nxapi transport') - instance['https'] = 'https_port' in resp[0] - instance['https_port'] = resp[0].get('https_port') or 443 + for key in ['config']: + if module.params[key]: + warnings.append('argument %s is deprecated and will be ignored' % key) - instance['sandbox'] = resp[0]['sandbox_status'] + return warnings - return instance +def map_obj_to_commands(updates, module): + commands = list() + want, have = updates -def present(module, instance, commands): - commands.append('feature nxapi') - setters = set() - for key, value in module.argument_spec.items(): - setter = value.get('setter') or 'set_%s' % key - if setter not in setters: - setters.add(setter) - if module.params[key] is not None: - invoke(setter, module, instance, commands) + needs_update = lambda x: want.get(x) is not None and (want.get(x) != have.get(x)) -def absent(module, instance, commands): - if instance['state'] != 'absent': - commands.append('no feature nxapi') + if needs_update('state'): + if want['state'] == 'absent': + return ['no feature nxapi'] + commands.append('feature nxapi') -def set_http(module, instance, commands): - port = module.params['http_port'] - if not 0 <= port <= 65535: + if any((needs_update('http'), needs_update('http_port'))): + if want['http'] is True or (want['http'] is None and have['http'] is True): + port = want['http_port'] or 80 + commands.append('nxapi http port %s' % port) + elif want['http'] is False: + commands.append('no nxapi http') + + if any((needs_update('https'), needs_update('https_port'))): + if want['https'] is True or (want['https'] is None and have['https'] is True): + port = want['https_port'] or 443 + commands.append('nxapi https port %s' % port) + elif want['https'] is False: + commands.append('no nxapi https') + + if needs_update('sandbox'): + cmd = 'nxapi sandbox' + if not want['sandbox']: + cmd = 'no %s' % cmd + commands.append(cmd) + + return commands + +def parse_http(data): + match = re.search('HTTP Port:\s+(\d+)', data, re.M) + if match: + return {'http': True, 'http_port': match.group(1)} + else: + return {'http': False, 'http_port': None} + +def parse_https(data): + match = re.search('HTTPS Port:\s+(\d+)', data, re.M) + if match: + return {'https': True, 'https_port': match.group(1)} + else: + return {'https': False, 'https_port': None} + +def parse_sandbox(data): + match = re.search('Sandbox:\s+(.+)$', data, re.M) + return {'sandbox': match.group(1) == 'Enabled'} + +def map_config_to_obj(module): + out = run_commands(module, ['show nxapi'], check_rc=False) + if not out[0]: + return {'state': 'absent'} + + out = str(out[0]).strip() + + obj = {'state': 'present'} + obj.update(parse_http(out)) + obj.update(parse_https(out)) + obj.update(parse_sandbox(out)) + + return obj + +def validate_http_port(value, module): + if not 1 <= module.params['http_port'] <= 65535: module.fail_json(msg='http_port must be between 1 and 65535') - elif module.params['http'] is True: - commands.append('nxapi http port %s' % port) - elif module.params['http'] is False: - commands.append('no nxapi http') -def set_https(module, instance, commands): - port = module.params['https_port'] - if not 0 <= port <= 65535: +def validate_https_port(value, module): + if not 1 <= module.params['https_port'] <= 65535: module.fail_json(msg='https_port must be between 1 and 65535') - elif module.params['https'] is True: - commands.append('nxapi https port %s' % port) - elif module.params['https'] is False: - commands.append('no nxapi https') -def set_sandbox(module, instance, commands): - if module.params['sandbox'] is True: - commands.append('nxapi sandbox') - elif module.params['sandbox'] is False: - commands.append('no nxapi sandbox') +def map_params_to_obj(module): + obj = { + 'http': module.params['http'], + 'http_port': module.params['http_port'], + 'https': module.params['https'], + 'https_port': module.params['https_port'], + 'sandbox': module.params['sandbox'], + 'state': module.params['state'] + } -def get_config(module): - contents = module.params['config'] - if not contents: - try: - contents = module.cli(['show running-config nxapi all'])[0] - except NetworkError: - contents = None - config = NetworkConfig(indent=2) - if contents: - config.load(contents) - return config - -def load_checkpoint(module, result): - try: - checkpoint = result['__checkpoint__'] - module.cli(['rollback running-config checkpoint %s' % checkpoint, - 'no checkpoint %s' % checkpoint], output='text') - except KeyError: - module.fail_json(msg='unable to rollback, checkpoint not found') - except NetworkError: - exc = get_exception() - msg = 'unable to rollback configuration' - module.fail_json(msg=msg, checkpoint=checkpoint, **exc.kwargs) - -def load_config(module, commands, result): - # create a config checkpoint - checkpoint = 'ansible_%s' % int(time.time()) - module.cli(['checkpoint %s' % checkpoint], output='text') - result['__checkpoint__'] = checkpoint - - # load the config into the device - module.config.load_config(commands) - - # load was successfully, remove the config checkpoint - module.cli(['no checkpoint %s' % checkpoint]) - -def load(module, commands, result): - candidate = NetworkConfig(indent=2, contents='\n'.join(commands)) - config = get_config(module) - configobjs = candidate.difference(config) - - if configobjs: - commands = dumps(configobjs, 'commands').split('\n') - result['updates'] = commands - if not module.check_mode: - load_config(module, commands, result) - result['changed'] = True - -def clean_result(result): - # strip out any keys that have two leading and two trailing - # underscore characters - for key in result.keys(): - if PRIVATE_KEYS_RE.match(key): - del result[key] + for key, value in iteritems(obj): + if value: + validator = globals().get('validate_%s' % key) + if validator: + validator(value, module) + return obj def main(): """ main entry point for module execution """ - argument_spec = dict( - http=dict(aliases=['enable_http'], default=True, type='bool', setter='set_http'), - http_port=dict(default=80, type='int', setter='set_http'), + http=dict(aliases=['enable_http'], type='bool'), + http_port=dict(type='int'), - https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'), - https_port=dict(default=443, type='int', setter='set_https'), + https=dict(aliases=['enable_https'], type='bool'), + https_port=dict(type='int'), - sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'), - - # Only allow configuration of NXAPI using cli transport - transport=dict(required=True, choices=['cli']), + sandbox=dict(aliases=['enable_sandbox'], type='bool'), + # deprecated (Ansible 2.3) arguments config=dict(), - # Support for started and stopped is for backwards capability only and - # will be removed in a future version state=dict(default='present', choices=['started', 'stopped', 'present', 'absent']) ) - module = NetworkModule(argument_spec=argument_spec, - connect_on_load=False, + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) - state = module.params['state'] + + result = {'changed': False} warnings = list() + check_args(module, warnings) + result['warnings'] = warnings - result = dict(changed=False, warnings=warnings) + want = map_params_to_obj(module) + have = map_config_to_obj(module) - if state == 'started': - state = 'present' - warnings.append('state=started is deprecated and will be removed in a ' - 'a future release. Please use state=present instead') - elif state == 'stopped': - state = 'absent' - warnings.append('state=stopped is deprecated and will be removed in a ' - 'a future release. Please use state=absent instead') + commands = map_obj_to_commands((want, have), module) + result['commands'] = commands - commands = list() - instance = get_instance(module) + if commands: + if not module.check_mode: + load_config(module, commands) + result['changed'] = True - invoke(state, module, instance, commands) - - try: - load(module, commands, result) - except (ValueError, NetworkError): - load_checkpoint(module, result) - exc = get_exception() - module.fail_json(msg=str(exc), **exc.kwargs) - - clean_result(result) module.exit_json(**result) - if __name__ == '__main__': main() diff --git a/lib/ansible/modules/network/nxos/nxos_ospf.py b/lib/ansible/modules/network/nxos/nxos_ospf.py index ead87ee71d..a0a98ae942 100644 --- a/lib/ansible/modules/network/nxos/nxos_ospf.py +++ b/lib/ansible/modules/network/nxos/nxos_ospf.py @@ -28,7 +28,6 @@ short_description: Manages configuration of an ospf instance. description: - Manages configuration of an ospf instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: ospf: description: @@ -81,156 +80,13 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { 'ospf': 'router ospf' @@ -304,9 +160,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] ospf = str(module.params['ospf']) @@ -345,3 +208,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py index 81d77e1c13..c0edc9a42d 100644 --- a/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py +++ b/lib/ansible/modules/network/nxos/nxos_ospf_vrf.py @@ -28,7 +28,6 @@ short_description: Manages a VRF for an OSPF router. description: - Manages a VRF for an OSPF router. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Value I(default) restores params default value, if any. Otherwise it removes the existing param configuration. @@ -172,156 +171,13 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.network import NetworkModule -from ansible.module_utils.shell import ShellError - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { @@ -527,9 +383,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ 'vrf', @@ -591,3 +454,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_overlay_global.py b/lib/ansible/modules/network/nxos/nxos_overlay_global.py index 5d31b049a8..01ba9d9278 100644 --- a/lib/ansible/modules/network/nxos/nxos_overlay_global.py +++ b/lib/ansible/modules/network/nxos/nxos_overlay_global.py @@ -28,7 +28,6 @@ short_description: Configures anycast gateway MAC of the switch. description: - Configures anycast gateway MAC of the switch. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default restores params default value - Supported MAC address format are "E.E.E", "EE-EE-EE-EE-EE-EE", @@ -109,159 +108,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig PARAM_TO_COMMAND_KEYMAP = { 'anycast_gateway_mac': 'fabric forwarding anycast-gateway-mac', @@ -372,12 +223,15 @@ def main(): argument_spec = dict( anycast_gateway_mac=dict(required=True, type='str'), m_facts=dict(required=False, default=False, type='bool'), - include_defaults=dict(default=True), - config=dict(), - save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) args = [ 'anycast_gateway_mac' @@ -392,22 +246,20 @@ def main(): candidate = CustomNetworkConfig(indent=3) invoke('get_commands', module, existing, proposed, candidate) - try: - response = load_config(module, candidate) - result.update(response) - except ShellError: - exc = get_exception() - module.fail_json(msg=str(exc)) + if not module.check_mode: + load_config(module, candidate) - result['connected'] = module.connected if module._verbosity > 0: end_state = invoke('get_existing', module, args) result['end_state'] = end_state result['existing'] = existing result['proposed'] = proposed + result['warnings'] = True + module.exit_json(**result) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim.py b/lib/ansible/modules/network/nxos/nxos_pim.py index 74e679bbaf..d3f13913d3 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim.py +++ b/lib/ansible/modules/network/nxos/nxos_pim.py @@ -28,7 +28,6 @@ short_description: Manages configuration of a PIM instance. description: - Manages configuration of a Protocol Independent Multicast (PIM) instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos options: ssm_range: description: @@ -73,159 +72,13 @@ changed: ''' -# COMMON CODE FOR MIGRATION import re +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re PARAM_TO_COMMAND_KEYMAP = { @@ -291,9 +144,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + splitted_ssm_range = module.params['ssm_range'].split('.') if len(splitted_ssm_range) != 4 and module.params['ssm_range'] != 'none': module.fail_json(msg="Valid ssm_range values are multicast addresses " @@ -334,3 +194,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim_interface.py b/lib/ansible/modules/network/nxos/nxos_pim_interface.py index ba90299a9e..4db51f94be 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_pim_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages PIM interface configuration. description: - Manages PIM interface configuration settings. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -187,232 +186,15 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + import time -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module, text=False): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n' or '^' in response[0]: - body = [] - elif 'show run' in command or text: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show', text=False): @@ -420,11 +202,10 @@ def execute_show_command(command, module, command_type='cli_show', text=False): if 'show run' not in command and text is False: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module, text=text) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -814,9 +595,16 @@ def main(): state=dict(choices=['present', 'absent', 'default'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] sparse = module.params['sparse'] @@ -912,7 +700,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) time.sleep(1) get_existing = get_pim_interface(module, interface) end_state, jp_bidir, isauth = local_existing(get_existing) @@ -923,6 +711,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -930,3 +719,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py index f32bee8dfb..3a6287bb00 100644 --- a/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py +++ b/lib/ansible/modules/network/nxos/nxos_pim_rp_address.py @@ -29,7 +29,6 @@ description: - Manages configuration of an Protocol Independent Multicast (PIM) static rendezvous point (RP) address instance. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - C(state=absent) remove the whole rp-address configuration, if existing. options: @@ -103,159 +102,13 @@ changed: -# COMMON CODE FOR MIGRATION import re +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re BOOL_PARAMS = ['bidir'] PARAM_TO_COMMAND_KEYMAP = { @@ -357,12 +210,19 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['group_list', 'route_map'], ['group_list', 'prefix_list'], ['route_map', 'prefix_list']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ @@ -414,3 +274,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_ping.py b/lib/ansible/modules/network/nxos/nxos_ping.py index 3a9b628f94..a3a7cc7419 100644 --- a/lib/ansible/modules/network/nxos/nxos_ping.py +++ b/lib/ansible/modules/network/nxos/nxos_ping.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Tests reachability using ping from Nexus switch. description: - Tests reachability using ping from switch to a remote destination. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -115,163 +114,9 @@ packet_loss: type: string sample: "0.00%" ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def get_summary(results_list, reference_point): summary_string = results_list[reference_point+1] @@ -313,48 +158,9 @@ def get_statistics_summary_line(response_as_list): return index -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command_ping(command, module, command_type='cli_show_ascii'): - cmds = [command] - if module.params['transport'] == 'cli': - body = execute_show(cmds, module) - elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) - return body - - def get_ping_results(command, module, transport): - ping = execute_show_command_ping(command, module)[0] + cmd = {'command': command, 'output': 'text'} + ping = run_commands(module, [cmd])[0] if not ping: module.fail_json(msg="An unexpected error occurred. Check all params.", @@ -388,9 +194,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + destination = module.params['dest'] count = module.params['count'] vrf = module.params['vrf'] @@ -444,3 +257,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_portchannel.py b/lib/ansible/modules/network/nxos/nxos_portchannel.py index 863e992dd2..1b820f0a72 100644 --- a/lib/ansible/modules/network/nxos/nxos_portchannel.py +++ b/lib/ansible/modules/network/nxos/nxos_portchannel.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages port-channel interfaces. description: - Manages port-channel specific configuration parameters. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -125,162 +124,15 @@ changed: sample: true ''' +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + import collections -import json -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re WARNINGS = [] PARAM_TO_COMMAND_KEYMAP = { 'min_links': 'lacp min-links' @@ -326,75 +178,15 @@ def get_custom_value(arg, config, module): return value -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - -def get_cli_body_ssh(command, response, module): - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show port-channel summary' in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -654,9 +446,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + group = str(module.params['group']) mode = module.params['mode'] min_links = module.params['min_links'] @@ -723,7 +522,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - output = execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state, interface_exist = get_existing(module, args) if 'configure' in cmds: @@ -735,6 +534,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings if WARNINGS: results['warnings'] = WARNINGS @@ -744,3 +544,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_reboot.py b/lib/ansible/modules/network/nxos/nxos_reboot.py index f113873fd0..db24e5b9a7 100644 --- a/lib/ansible/modules/network/nxos/nxos_reboot.py +++ b/lib/ansible/modules/network/nxos/nxos_reboot.py @@ -27,7 +27,6 @@ version_added: 2.2 short_description: Reboot a network device. description: - Reboot a network device. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -58,244 +57,40 @@ rebooted: sample: true ''' -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule def reboot(module): - disable_confirmation(module) - execute_show_command(['reload'], module, command_type='cli_show_ascii') - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - body = execute_show(command, module) - elif module.params['transport'] == 'nxapi': - body = execute_show(command, module, command_type=command_type) - - return body - - -def disable_confirmation(module): - command = ['terminal dont-ask'] - body = execute_show_command(command, module, command_type='cli_show_ascii')[0] - + cmds = [ + {'command': 'terminal-dont-ask'}, + {'command': 'reload', 'output': 'text'} + ] + run_commands(module, cmds) def main(): - argument_spec = dict( - confirm=dict(required=True, type='bool'), - include_defaults=dict(default=False), - config=dict(), - save=dict(type='bool', default=False) - ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + argument_spec = {} + argument_spec.update(nxos_argument_spec) - confirm = module.params['confirm'] - if not confirm: - module.fail_json(msg='confirm must be set to true for this ' - 'module to work.') + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) - changed = False - rebooted = False - - reboot(module) + warnings = list() + check_args(module, warnings) + if not module.check_mode: + reboot(module) changed = True - rebooted = True - results = {} - results['changed'] = changed - results['rebooted'] = rebooted + results = { + 'changed': True, + 'warnings': warnings + } module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_rollback.py b/lib/ansible/modules/network/nxos/nxos_rollback.py index a429e1992f..19348e1371 100644 --- a/lib/ansible/modules/network/nxos/nxos_rollback.py +++ b/lib/ansible/modules/network/nxos/nxos_rollback.py @@ -29,7 +29,6 @@ description: - This module offers the ability to set a configuration checkpoint file or rollback to a configuration checkpoint file on Cisco NXOS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -77,159 +76,13 @@ status: ''' -# COMMON CODE FOR MIGRATION import re +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re def execute_commands(cmds, module, command_type=None): @@ -297,7 +150,10 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['checkpoint_file', 'rollback_to']], supports_check_mode=False) @@ -326,3 +182,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_smu.py b/lib/ansible/modules/network/nxos/nxos_smu.py index 76c72f2b0c..86e4229477 100644 --- a/lib/ansible/modules/network/nxos/nxos_smu.py +++ b/lib/ansible/modules/network/nxos/nxos_smu.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Perform SMUs on Cisco NX-OS devices. description: - Perform software maintenance upgrades (SMUs) on Cisco NX-OS devices. -extends_documentation_fragment: nxos author: Gabriele Gerbino (@GGabriele) notes: - The module can only activate and commit a package, @@ -80,202 +79,24 @@ changed: sample: true ''' +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + import time -import json import collections -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +import re def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': cmds = [command] - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -288,28 +109,9 @@ def remote_file_exists(module, dst, file_system='bootflash:'): return True -def execute_config_command(commands, module): - try: - output = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - output = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return output - - def apply_patch(module, commands): for command in commands: - response = execute_config_command([command], module) + load_config(module, [command]) time.sleep(5) if 'failed' in response: module.fail_json(msg="Operation failed!", response=response) @@ -350,9 +152,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + pkg = module.params['pkg'] file_system = module.params['file_system'] changed = False @@ -382,3 +191,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snapshot.py b/lib/ansible/modules/network/nxos/nxos_snapshot.py index 61dd094b51..fb9a9c64d6 100644 --- a/lib/ansible/modules/network/nxos/nxos_snapshot.py +++ b/lib/ansible/modules/network/nxos/nxos_snapshot.py @@ -29,7 +29,6 @@ description: - Create snapshots of the running states of selected features, add new show commands for snapshot creation, delete and compare existing snapshots. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -209,199 +208,22 @@ changed: sample: true ''' +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + import os -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show_ascii'): cmds = [command] if module.params['transport'] == 'cli': - body = execute_show(cmds, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -535,24 +357,6 @@ def invoke(name, *args, **kwargs): return func(*args, **kwargs) -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - def get_snapshot(module): command = 'show snapshot dump {0}'.format(module.params['snapshot_name']) body = execute_show_command(command, module)[0] @@ -594,11 +398,18 @@ def main(): default=False), path=dict(required=False, type='str', default='./') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['delete_all', 'delete_snapshot']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + action = module.params['action'] comparison_results_file = module.params['comparison_results_file'] @@ -647,7 +458,7 @@ def main(): result['updates'] = [] else: if action_results: - execute_config_command(action_results, module) + load_config(module, action_results) changed = True final_snapshots = invoke('get_existing', module) result['updates'] = action_results @@ -672,3 +483,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_community.py b/lib/ansible/modules/network/nxos/nxos_snmp_community.py index aac8c02ef6..3f42b2f6c0 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_community.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_community.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP community configs. description: - Manages SNMP community configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -98,231 +97,14 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -330,11 +112,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -435,11 +216,18 @@ def main(): acl=dict(type='str'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['access', 'group']], mutually_exclusive=[['access', 'group']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + access = module.params['access'] group = module.params['group'] community = module.params['community'] @@ -484,7 +272,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_community(module, community) if 'configure' in cmds: cmds.pop(0) @@ -495,9 +283,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_contact.py b/lib/ansible/modules/network/nxos/nxos_snmp_contact.py index 02601c6de6..e5d8a08d03 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_contact.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_contact.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP contact info. description: - Manages SNMP contact information. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -83,231 +82,14 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -315,11 +97,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -357,9 +138,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + contact = module.params['contact'] state = module.params['state'] @@ -382,7 +170,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_contact(module) if 'configure' in cmds: cmds.pop(0) @@ -393,9 +181,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_host.py b/lib/ansible/modules/network/nxos/nxos_snmp_host.py index 8643b4da7c..c38945a489 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_host.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_host.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP host configuration. description: - Manages SNMP host configuration parameters. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -131,231 +130,14 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -363,11 +145,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -540,9 +321,16 @@ def main(): snmp_type=dict(choices=['trap', 'inform'], default='trap'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + snmp_host = module.params['snmp_host'] community = module.params['community'] @@ -620,7 +408,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_host(snmp_host, module) if 'configure' in cmds: cmds.pop(0) @@ -634,9 +422,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_location.py b/lib/ansible/modules/network/nxos/nxos_snmp_location.py index 7f6e46e033..d415c4e6b8 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_location.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_location.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP location information. description: - Manages SNMP location configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -90,231 +89,14 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -322,11 +104,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -376,9 +157,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + location = module.params['location'] state = module.params['state'] @@ -402,7 +190,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_location(module) if 'configure' in cmds: cmds.pop(0) @@ -413,6 +201,7 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) @@ -420,3 +209,4 @@ def main(): from ansible.module_utils.basic import * if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_traps.py b/lib/ansible/modules/network/nxos/nxos_snmp_traps.py index d9e8ec5b21..11f829d4f4 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_traps.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_traps.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages SNMP traps. description: - Manages SNMP traps configurations. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -101,231 +100,14 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -333,11 +115,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -461,9 +242,16 @@ def main(): 'sysmgr', 'system', 'upgrade', 'vtp', 'all'], required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + group = module.params['group'].lower() state = module.params['state'] @@ -480,7 +268,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_traps(group, module) if 'configure' in cmds: cmds.pop(0) @@ -491,9 +279,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_snmp_user.py b/lib/ansible/modules/network/nxos/nxos_snmp_user.py index 5520a7d8dc..5e084bd211 100644 --- a/lib/ansible/modules/network/nxos/nxos_snmp_user.py +++ b/lib/ansible/modules/network/nxos/nxos_snmp_user.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages SNMP users for monitoring. description: - Manages SNMP user configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -112,231 +111,14 @@ changed: type: boolean sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module, text=False): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command or text: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show', text=False): @@ -344,11 +126,10 @@ def execute_show_command(command, module, command_type='cli_show', text=False): if 'show run' not in command and text is False: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module, text=text) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -462,11 +243,18 @@ def main(): encrypt=dict(type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_together=[['authentication', 'pwd'], ['encrypt', 'privacy']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + user = module.params['user'] group = module.params['group'] pwd = module.params['pwd'] @@ -540,7 +328,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_snmp_user(user, module) if 'configure' in cmds: cmds.pop(0) @@ -552,6 +340,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -559,3 +348,4 @@ def main(): if __name__ == "__main__": main() + diff --git a/lib/ansible/modules/network/nxos/nxos_static_route.py b/lib/ansible/modules/network/nxos/nxos_static_route.py index ed0bcdd25a..974e902b09 100644 --- a/lib/ansible/modules/network/nxos/nxos_static_route.py +++ b/lib/ansible/modules/network/nxos/nxos_static_route.py @@ -27,7 +27,6 @@ short_description: Manages static route configuration description: - Manages static route configuration author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - If no vrf is supplied, vrf is set to default. - If C(state=absent), the route will be removed, regardless of the @@ -111,159 +110,12 @@ changed: type: boolean sample: true ''' - -# COMMON CODE FOR MIGRATION import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine, dumps -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - if self._device_os == 'junos': - return dumps(section, output='lines') - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def invoke(name, *args, **kwargs): func = globals().get(name) @@ -429,8 +281,13 @@ def main(): save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - supports_check_mode=True) + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) state = module.params['state'] @@ -448,12 +305,7 @@ def main(): candidate = CustomNetworkConfig(indent=3) invoke('state_%s' % state, module, candidate, prefix) - try: - response = load_config(module, candidate) - result.update(response) - except Exception: - exc = get_exception() - module.fail_json(msg=str(exc)) + load_config(module, candidate) else: result['updates'] = [] @@ -470,3 +322,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_switchport.py b/lib/ansible/modules/network/nxos/nxos_switchport.py index d02f7e7660..cc05870a40 100644 --- a/lib/ansible/modules/network/nxos/nxos_switchport.py +++ b/lib/ansible/modules/network/nxos/nxos_switchport.py @@ -25,7 +25,6 @@ DOCUMENTATION = ''' module: nxos_switchport version_added: "2.1" short_description: Manages Layer 2 switchport interfaces. -extends_documentation_fragment: nxos description: - Manages Layer 2 interfaces author: Jason Edelman (@jedelman8) @@ -154,161 +153,14 @@ changed: sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +import re def get_interface_type(interface): """Gets the type of interface @@ -605,86 +457,15 @@ def apply_value_map(value_map, resource): return resource -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -711,12 +492,19 @@ def main(): state=dict(choices=['absent', 'present', 'unconfigured'], default='present') ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['access_vlan', 'trunk_vlans'], ['access_vlan', 'native_vlan'], ['access_vlan', 'trunk_allowed_vlans']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'] mode = module.params['mode'] access_vlan = module.params['access_vlan'] @@ -817,7 +605,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_switchport(interface, module) if 'configure' in cmds: cmds.pop(0) @@ -828,8 +616,10 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_udld.py b/lib/ansible/modules/network/nxos/nxos_udld.py index 06d6d4176b..959eb3672e 100644 --- a/lib/ansible/modules/network/nxos/nxos_udld.py +++ b/lib/ansible/modules/network/nxos/nxos_udld.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages UDLD global configuration params. description: - Manages UDLD global configuration params. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -108,231 +107,14 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -340,11 +122,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -435,10 +216,17 @@ def main(): reset=dict(required=False, type='bool'), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, required_one_of=[['aggressive', 'msg_time', 'reset']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + aggressive = module.params['aggressive'] msg_time = module.params['msg_time'] reset = module.params['reset'] @@ -486,7 +274,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_udld_global(module) if 'configure' in cmds: cmds.pop(0) @@ -497,9 +285,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_udld_interface.py b/lib/ansible/modules/network/nxos/nxos_udld_interface.py index 37230e3e2c..a3d5e1ba4c 100644 --- a/lib/ansible/modules/network/nxos/nxos_udld_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_udld_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages UDLD interface configuration params. description: - Manages UDLD interface configuration params. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) notes: @@ -107,231 +106,14 @@ changed: ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -339,11 +121,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -466,9 +247,16 @@ def main(): interface=dict(type='str', required=True), state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + interface = module.params['interface'].lower() mode = module.params['mode'] state = module.params['state'] @@ -500,7 +288,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_udld_interface(module, interface) if 'configure' in cmds: cmds.pop(0) @@ -511,8 +299,10 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_user.py b/lib/ansible/modules/network/nxos/nxos_user.py new file mode 100644 index 0000000000..c527d4bfdd --- /dev/null +++ b/lib/ansible/modules/network/nxos/nxos_user.py @@ -0,0 +1,357 @@ +#!/usr/bin/python +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +ANSIBLE_METADATA = { + 'status': ['preview'], + 'supported_by': 'core', + 'version': '1.0' +} + +DOCUMENTATION = """ +--- +module: nxos_user +version_added: "2.3" +author: "Peter Sprygada (@privateip)" +short_description: Manage the collection of local users on Nexus devices +description: + - This module provides declarative management of the local usernames + configured on Cisco Nexus devices. It allows playbooks to manage + either individual usernames or the collection of usernames in the + current running config. It also supports purging usernames from the + configuration that are not explicitly defined. +options: + users: + description: + - The set of username objects to be configured on the remote + Cisco Nexus device. The list entries can either be the username + or a hash of username and properties. This argument is mutually + exclusive with the C(name) argument. + required: false + default: null + name: + description: + - The username to be configured on the remote Cisco Nexus + device. This argument accepts a stringv value and is mutually + exclusive with the C(users) argument. + required: false + default: null + update_password: + description: + - Since passwords are encrypted in the device running config, this + argument will instruct the module when to change the password. When + set to C(always), the password will always be updated in the device + and when set to C(on_create) the password will be updated only if + the username is created. + required: false + default: always + choices: ['on_create', 'always'] + role: + description: + - The C(role) argument configures the role for the username in the + device running configuration. The argument accepts a string value + defining the role name. This argument does not check if the role + has been configured on the device. + required: false + default: null + sshkey: + description: + - The C(sshkey) argument defines the SSH public key to configure + for the username. This argument accepts a valid SSH key value. + required: false + default: null + purge: + description: + - The C(purge) argument instructs the module to consider the + resource definition absolute. It will remove any previously + configured usernames on the device with the exception of the + `admin` user which cannot be deleted per nxos constraints. + required: false + default: false + state: + description: + - The C(state) argument configures the state of the username definition + as it relates to the device operational configuration. When set + to I(present), the username(s) should be configured in the device active + configuration and when set to I(absent) the username(s) should not be + in the device active configuration + required: false + default: present + choices: ['present', 'absent'] +""" + +EXAMPLES = """ +- name: create a new user + nxos_user: + name: ansible + sshkey: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}" + state: present + +- name: remove all users except admin + nxos_user: + purge: yes + +- name: set multiple users role + users: + - name: netop + - name: netend + role: network-operator + state: present +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - name ansible + - name ansible password password +start: + description: The time the job started + returned: always + type: str + sample: "2016-11-16 10:38:15.126146" +end: + description: The time the job ended + returned: always + type: str + sample: "2016-11-16 10:38:25.595612" +delta: + description: The time elapsed to perform all operations + returned: always + type: str + sample: "0:00:10.469466" +""" +import re + +from functools import partial + +from ansible.module_utils.nxos import run_commands, load_config +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.six import string_types, iteritems +from ansible.module_utils.network_common import to_list + +VALID_ROLES = ['network-admin', 'network-operator', 'vdc-admin', 'vdc-operator', + 'priv-15', 'priv-14', 'priv-13', 'priv-12', 'priv-11', 'priv-10', + 'priv-9', 'priv-8', 'priv-7', 'priv-6', 'priv-5', 'priv-4', + 'priv-3', 'priv-2', 'priv-1', 'priv-0'] + + +def validate_roles(value, module): + for item in value: + if item not in VALID_ROLES: + module.fail_json(msg='invalid role specified') + +def map_obj_to_commands(updates, module): + commands = list() + state = module.params['state'] + update_password = module.params['update_password'] + + for update in updates: + want, have = update + + needs_update = lambda x: want.get(x) and (want.get(x) != have.get(x)) + add = lambda x: commands.append('username %s %s' % (want['name'], x)) + remove = lambda x: commands.append('no username %s %s' % (want['name'], x)) + + if want['state'] == 'absent': + commands.append('no username %s' % want['name']) + continue + + if want['state'] == 'present' and not have: + commands.append('username %s' % want['name']) + + if needs_update('password'): + if update_password == 'always' or not have: + add('password %s' % want['password']) + + if needs_update('sshkey'): + add('sshkey %s' % want['sshkey']) + + + if want['roles']: + if have: + for item in set(have['roles']).difference(want['roles']): + remove('role %s' % item) + + for item in set(want['roles']).difference(have['roles']): + add('role %s' % item) + else: + for item in want['roles']: + add('role %s' % item) + + + return commands + +def parse_password(data): + if not data.get('remote_login'): + return '' + +def parse_roles(data): + configured_roles = data.get('TABLE_role')['ROW_role'] + roles = list() + if configured_roles: + for item in to_list(configured_roles): + roles.append(item['role']) + return roles + +def map_config_to_obj(module): + out = run_commands(module, ['show user-account | json']) + data = out[0] + + objects = list() + + for item in to_list(data['TABLE_template']['ROW_template']): + objects.append({ + 'name': item['usr_name'], + 'password': parse_password(item), + 'sshkey': item.get('sshkey_info'), + 'roles': parse_roles(item), + 'state': 'present' + }) + return objects + +def get_param_value(key, item, module): + # if key doesn't exist in the item, get it from module.params + if not item.get(key): + value = module.params[key] + + # if key does exist, do a type check on it to validate it + else: + value_type = module.argument_spec[key].get('type', 'str') + type_checker = module._CHECK_ARGUMENT_TYPES_DISPATCHER[value_type] + type_checker(item[key]) + value = item[key] + + return value + +def map_params_to_obj(module): + users = module.params['users'] + if not users: + if not module.params['name'] and module.params['purge']: + return list() + elif not module.params['name']: + module.fail_json(msg='username is required') + else: + collection = [{'name': module.params['name']}] + else: + collection = list() + for item in users: + if not isinstance(item, dict): + collection.append({'name': item}) + elif 'name' not in item: + module.fail_json(msg='name is required') + else: + collection.append(item) + + objects = list() + + for item in collection: + get_value = partial(get_param_value, item=item, module=module) + item.update({ + 'password': get_value('password'), + 'sshkey': get_value('sshkey'), + 'roles': get_value('roles'), + 'state': get_value('state') + }) + + for key, value in iteritems(item): + if value: + # validate the param value (if validator func exists) + validator = globals().get('validate_%s' % key) + if all((value, validator)): + validator(value, module) + + objects.append(item) + + return objects + +def update_objects(want, have): + updates = list() + for entry in want: + item = next((i for i in have if i['name'] == entry['name']), None) + if all((item is None, entry['state'] == 'present')): + updates.append((entry, {})) + elif item: + for key, value in iteritems(entry): + if value and value != item[key]: + updates.append((entry, item)) + return updates + +def main(): + """ main entry point for module execution + """ + argument_spec = dict( + users=dict(type='list', no_log=True), + name=dict(), + + password=dict(no_log=True), + update_password=dict(default='always', choices=['on_create', 'always']), + + roles=dict(type='list'), + + sshkey=dict(), + + purge=dict(type='bool', default=False), + state=dict(default='present', choices=['present', 'absent']) + ) + + argument_spec.update(nxos_argument_spec) + + mutually_exclusive = [('name', 'users')] + + module = AnsibleModule(argument_spec=argument_spec, + mutually_exclusive=mutually_exclusive, + supports_check_mode=True) + + + result = {'changed': False} + + warnings = list() + check_args(module, warnings) + result['warnings'] = warnings + + want = map_params_to_obj(module) + have = map_config_to_obj(module) + + commands = map_obj_to_commands(update_objects(want, have), module) + + if module.params['purge']: + want_users = [x['name'] for x in want] + have_users = [x['name'] for x in have] + for item in set(have_users).difference(want_users): + if item != 'admin': + commands.append('no username %s' % item) + + result['commands'] = commands + + # the nxos cli prevents this by rule so capture it and display + # a nice failure message + if 'no username admin' in commands: + module.fail_json(msg='cannot delete the `admin` account') + + if commands: + if not module.check_mode: + load_config(module, commands) + result['changed'] = True + + module.exit_json(**result) + +if __name__ == '__main__': + main() diff --git a/lib/ansible/modules/network/nxos/nxos_vlan.py b/lib/ansible/modules/network/nxos/nxos_vlan.py index 6e350b89fb..1db2ea9d85 100644 --- a/lib/ansible/modules/network/nxos/nxos_vlan.py +++ b/lib/ansible/modules/network/nxos/nxos_vlan.py @@ -28,7 +28,6 @@ short_description: Manages VLAN resources and attributes. description: - Manages VLAN configurations on NX-OS switches. author: Jason Edelman (@jedelman8) -extends_documentation_fragment: nxos options: vlan_id: description: @@ -153,163 +152,15 @@ changed: sample: true ''' +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.nxos import run_commands, load_config, get_config +from ansible.module_utils.basic import AnsibleModule def vlan_range_to_list(vlans): result = [] @@ -396,8 +247,7 @@ def get_vlan_config_commands(vlan, vid): def get_list_of_vlans(module): - command = 'show vlan' - body = execute_show_command(command, module) + body = run_commands(module, ['show vlan | json']) vlan_list = [] vlan_table = body[0].get('TABLE_vlanbrief')['ROW_vlanbrief'] @@ -411,8 +261,10 @@ def get_list_of_vlans(module): def get_vni(vlanid, module): - command = 'show run all | section vlan.{0}'.format(vlanid) - body = execute_show_command(command, module, command_type='cli_show_ascii')[0] + flags = str('all | section vlan.{0}'.format(vlanid)).split(' ') + body = get_config(module, flags=flags) + #command = 'show run all | section vlan.{0}'.format(vlanid) + #body = execute_show_command(command, module, command_type='cli_show_ascii')[0] value = '' if body: REGEX = re.compile(r'(?:vn-segment\s)(?P.*)$', re.M) @@ -424,10 +276,11 @@ def get_vni(vlanid, module): def get_vlan(vlanid, module): """Get instance of VLAN as a dictionary """ + command = 'show vlan id %s | json' % vlanid + body = run_commands(module, [command]) - command = 'show vlan id ' + vlanid - - body = execute_show_command(command, module) + #command = 'show vlan id ' + vlanid + #body = execute_show_command(command, module) try: vlan_table = body[0]['TABLE_vlanbriefid']['ROW_vlanbriefid'] @@ -469,90 +322,6 @@ def apply_value_map(value_map, resource): resource[key] = value[resource.get(key)] return resource - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. - """ - if 'show run' in command or response[0] == '\n': - body = response - elif 'xml' in response[0]: - body = [] - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - -def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': - if 'show run' not in command: - command += ' | json' - cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) - elif module.params['transport'] == 'nxapi': - cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - - return body - - def main(): argument_spec = dict( vlan_id=dict(required=False, type='str'), @@ -567,10 +336,23 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, - mutually_exclusive=[['vlan_range', 'name'], - ['vlan_id', 'vlan_range']], - supports_check_mode=True) + + argument_spec.update(nxos_argument_spec) + + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, + mutually_exclusive=[['vlan_range', 'name'], + ['vlan_id', 'vlan_range']], + supports_check_mode=True) + + warnings = list() + check_args(module, warnings) + + + warnings = list() + check_args(module, warnings) vlan_range = module.params['vlan_range'] vlan_id = module.params['vlan_id'] @@ -636,7 +418,7 @@ def main(): module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True end_state_vlans_list = numerical_sort(get_list_of_vlans(module)) if 'configure' in commands: @@ -653,9 +435,12 @@ def main(): results['end_state_vlans_list'] = end_state_vlans_list results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vpc.py b/lib/ansible/modules/network/nxos/nxos_vpc.py index 87bde5ad67..9e243d8ae7 100644 --- a/lib/ansible/modules/network/nxos/nxos_vpc.py +++ b/lib/ansible/modules/network/nxos/nxos_vpc.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages global VPC configuration description: - Manages global VPC configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -145,243 +144,20 @@ changed: sample: true ''' -import json -import collections - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. - """ - if '^' == response[0]: - body = [] - elif 'running' in command: - body = response - else: - if command in response[0]: - response = [response[0].split(command)[1]] - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if "section" not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -577,9 +353,15 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + domain = module.params['domain'] role_priority = module.params['role_priority'] system_priority = module.params['system_priority'] @@ -640,7 +422,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vpc(module) if 'configure' in cmds: cmds.pop(0) @@ -651,9 +433,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py index 2ac23411a2..76bb532b49 100644 --- a/lib/ansible/modules/network/nxos/nxos_vpc_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_vpc_interface.py @@ -27,7 +27,6 @@ version_added: "2.2" short_description: Manages interface VPC configuration description: - Manages interface VPC configuration -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,240 +96,19 @@ changed: ''' -import collections -import json - -# COMMON CODE FOR MIGRATION -import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - response = module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - return response - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. - """ - if '^' == response[0]: - body = [] - elif 'running' in command or 'xml' in response[0]: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -485,10 +263,17 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, mutually_exclusive=[['vpc', 'peer_link']], supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + portchannel = module.params['portchannel'] vpc = module.params['vpc'] peer_link = module.params['peer_link'] @@ -570,7 +355,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - output = execute_config_command(cmds, module) + load_config(module, cmds) if module.params['transport'] == 'cli': output = ' '.join(output) if 'error' in output.lower(): @@ -585,9 +370,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf.py b/lib/ansible/modules/network/nxos/nxos_vrf.py index 899c4722ef..2f70a89c51 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages global VRF configuration. description: - Manages global VRF configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -117,238 +116,23 @@ changed: type: boolean sample: true ''' - -import json - -# COMMON CODE FOR MIGRATION import re -import ansible.module_utils.nxos -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError -from ansible.module_utils.network import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrf(module, command, response): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when using multiple |. - """ - command_splitted = command.split('|') - if len(command_splitted) > 2 or 'show run' in command: - body = response - elif 'xml' in response[0] or response[0] == '\n': - body = [] - else: - body = [json.loads(response[0])] - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): - if module.params['transport'] == 'cli': + transport = module.params['provider']['transport'] + if transport in ['cli', None]: if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrf(module, command, response) - elif module.params['transport'] == 'nxapi': + body = run_commands(module, cmds) + else: cmds = [command] - body = execute_show(cmds, module, command_type=command_type) - + body = run_commands(module, cmds) return body @@ -457,9 +241,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vrf = module.params['vrf'] admin_state = module.params['admin_state'].lower() description = module.params['description'] @@ -512,7 +303,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True end_state = get_vrf(vrf, module) if 'configure' in commands: @@ -524,9 +315,11 @@ def main(): results['end_state'] = end_state results['updates'] = commands results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_af.py b/lib/ansible/modules/network/nxos/nxos_vrf_af.py index 28d4e29c11..91072ec6ab 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf_af.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf_af.py @@ -28,7 +28,6 @@ short_description: Manages VRF AF. description: - Manages VRF AF author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - Default, where supported, restores params default value. options: @@ -104,159 +103,12 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = ['route_target_both_auto_evpn'] PARAM_TO_COMMAND_KEYMAP = { @@ -378,9 +230,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] args = [ @@ -434,3 +293,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py index b007040102..d6ea1a1043 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrf_interface.py +++ b/lib/ansible/modules/network/nxos/nxos_vrf_interface.py @@ -27,7 +27,6 @@ version_added: "2.1" short_description: Manages interface specific VRF configuration. description: - Manages interface specific VRF configuration. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -97,240 +96,25 @@ changed: type: boolean sample: true ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE WARNINGS = [] -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrf_interface(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. As such, - we assume if '^' is found in response, it is an invalid command. Instead, - the output will be a raw string when issuing commands containing 'show run'. - """ - if '^' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - body = [json.loads(response[0])] - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrf_interface(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -428,9 +212,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vrf = module.params['vrf'] interface = module.params['interface'].lower() state = module.params['state'] @@ -486,7 +277,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=commands) else: - execute_config_command(commands, module) + load_config(module, commands) changed = True changed_vrf = get_interface_info(interface, module) end_state = dict(interface=interface, vrf=changed_vrf) @@ -508,3 +299,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vrrp.py b/lib/ansible/modules/network/nxos/nxos_vrrp.py index 86f6a22375..ec6be83a08 100644 --- a/lib/ansible/modules/network/nxos/nxos_vrrp.py +++ b/lib/ansible/modules/network/nxos/nxos_vrrp.py @@ -28,7 +28,6 @@ version_added: "2.1" short_description: Manages VRRP configuration on NX-OS switches. description: - Manages VRRP configuration on NX-OS switches. -extends_documentation_fragment: nxos author: - Jason Edelman (@jedelman8) - Gabriele Gerbino (@GGabriele) @@ -135,245 +134,21 @@ changed: type: boolean sample: true ''' - -import json -import collections - -# COMMON CODE FOR MIGRATION import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh_vrrp(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0]: - body = [] - elif 'show run' in command: - body = response - else: - try: - response = response[0].replace(command + '\n\n', '').strip() - body = [json.loads(response)] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - - +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh_vrrp(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -587,9 +362,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'].lower() group = module.params['group'] @@ -648,7 +430,7 @@ def main(): if module.check_mode: module.exit_json(changed=True, commands=cmds) else: - execute_config_command(cmds, module) + load_config(module, cmds) changed = True end_state = get_existing_vrrp(interface, group, module, name) if 'configure' in cmds: @@ -659,6 +441,7 @@ def main(): results['existing'] = existing results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings results['end_state'] = end_state module.exit_json(**results) @@ -666,3 +449,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_domain.py b/lib/ansible/modules/network/nxos/nxos_vtp_domain.py index abd126858f..4ef6525a69 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_domain.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_domain.py @@ -26,7 +26,6 @@ version_added: "2.2" short_description: Manages VTP domain configuration. description: - Manages VTP domain configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -84,243 +83,22 @@ changed: ''' -import json - -# COMMON CODE FOR MIGRATION +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -380,9 +158,16 @@ def main(): argument_spec = dict( domain=dict(type='str', required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + domain = module.params['domain'] existing = get_vtp_config(module) @@ -404,7 +189,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -415,9 +200,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_password.py b/lib/ansible/modules/network/nxos/nxos_vtp_password.py index c1cfe1337e..cda74f6358 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_password.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_password.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages VTP password configuration. description: - Manages VTP password configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -101,243 +100,22 @@ changed: sample: true ''' -import json - -# COMMON CODE FOR MIGRATION +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig import re -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'show run' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response - def execute_show_command(command, module, command_type='cli_show'): if module.params['transport'] == 'cli': if 'show run' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -412,9 +190,16 @@ def main(): state=dict(choices=['absent', 'present'], default='present'), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + vtp_password = module.params['vtp_password'] or None state = module.params['state'] @@ -461,7 +246,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -472,9 +257,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vtp_version.py b/lib/ansible/modules/network/nxos/nxos_vtp_version.py index 0754c3bb26..c61df0bc25 100644 --- a/lib/ansible/modules/network/nxos/nxos_vtp_version.py +++ b/lib/ansible/modules/network/nxos/nxos_vtp_version.py @@ -28,7 +28,6 @@ version_added: "2.2" short_description: Manages VTP version configuration. description: - Manages VTP version configuration. -extends_documentation_fragment: nxos author: - Gabriele Gerbino (@GGabriele) notes: @@ -79,231 +78,14 @@ changed: type: boolean sample: true ''' -import json +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig + -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE - - -def execute_config_command(commands, module): - try: - module.configure(commands) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - except AttributeError: - try: - commands.insert(0, 'configure') - module.cli.add_commands(commands, output='config') - module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending CLI commands', - error=str(clie), commands=commands) - - -def get_cli_body_ssh(command, response, module): - """Get response for when transport=cli. This is kind of a hack and mainly - needed because these modules were originally written for NX-API. And - not every command supports "| json" when using cli/ssh. As such, we assume - if | json returns an XML string, it is a valid command, but that the - resource doesn't exist yet. Instead, the output will be a raw string - when issuing commands containing 'show run'. - """ - if 'xml' in response[0] or response[0] == '\n': - body = [] - elif 'status' in command: - body = response - else: - try: - body = [json.loads(response[0])] - except ValueError: - module.fail_json(msg='Command does not support JSON output', - command=command) - return body - - -def execute_show(cmds, module, command_type=None): - command_type_map = { - 'cli_show': 'json', - 'cli_show_ascii': 'text' - } - - try: - if command_type: - response = module.execute(cmds, command_type=command_type) - else: - response = module.execute(cmds) - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - except AttributeError: - try: - if command_type: - command_type = command_type_map.get(command_type) - module.cli.add_commands(cmds, output=command_type) - response = module.cli.run_commands() - else: - module.cli.add_commands(cmds, raw=True) - response = module.cli.run_commands() - except ShellError: - clie = get_exception() - module.fail_json(msg='Error sending {0}'.format(cmds), - error=str(clie)) - return response +import re def execute_show_command(command, module, command_type='cli_show'): @@ -311,11 +93,10 @@ def execute_show_command(command, module, command_type='cli_show'): if 'status' not in command: command += ' | json' cmds = [command] - response = execute_show(cmds, module) - body = get_cli_body_ssh(command, response, module) + body = run_commands(module, cmds) elif module.params['transport'] == 'nxapi': cmds = [command] - body = execute_show(cmds, module, command_type=command_type) + body = run_commands(module, cmds) return body @@ -375,9 +156,16 @@ def main(): argument_spec = dict( version=dict(type='str', choices=['1', '2'], required=True), ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + version = module.params['version'] existing = get_vtp_config(module) @@ -399,7 +187,7 @@ def main(): module.exit_json(changed=True, commands=cmds) else: changed = True - execute_config_command(cmds, module) + load_config(module, cmds) end_state = get_vtp_config(module) if 'configure' in cmds: cmds.pop(0) @@ -410,9 +198,11 @@ def main(): results['end_state'] = end_state results['updates'] = cmds results['changed'] = changed + results['warnings'] = warnings module.exit_json(**results) if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py index 08ac7692c7..eac3530471 100644 --- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py +++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep.py @@ -29,7 +29,6 @@ description: - Manages VXLAN Network Virtualization Endpoint (NVE) overlay interface that terminates VXLAN tunnels. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - The module is used to manage NVE properties, not to create NVE interfaces. Use M(nxos_interface) if you wish to do so. @@ -124,159 +123,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = [ 'shutdown', @@ -458,9 +309,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + state = module.params['state'] interface = module.params['interface'].lower() @@ -528,3 +386,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py index 4abfd33f8c..3e79eae8e8 100644 --- a/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py +++ b/lib/ansible/modules/network/nxos/nxos_vxlan_vtep_vni.py @@ -29,7 +29,6 @@ description: - Creates a Virtual Network Identifier member (VNI) for an NVE overlay interface. author: Gabriele Gerbino (@GGabriele) -extends_documentation_fragment: nxos notes: - default, where supported, restores params default value. options: @@ -143,159 +142,11 @@ changed: sample: true ''' -# COMMON CODE FOR MIGRATION import re - -from ansible.module_utils.basic import get_exception -from ansible.module_utils.netcfg import NetworkConfig, ConfigLine -from ansible.module_utils.shell import ShellError - -try: - from ansible.module_utils.nxos import get_module -except ImportError: - from ansible.module_utils.nxos import NetworkModule - - -def to_list(val): - if isinstance(val, (list, tuple)): - return list(val) - elif val is not None: - return [val] - else: - return list() - - -class CustomNetworkConfig(NetworkConfig): - - def expand_section(self, configobj, S=None): - if S is None: - S = list() - S.append(configobj) - for child in configobj.children: - if child in S: - continue - self.expand_section(child, S) - return S - - def get_object(self, path): - for item in self.items: - if item.text == path[-1]: - parents = [p.text for p in item.parents] - if parents == path[:-1]: - return item - - def to_block(self, section): - return '\n'.join([item.raw for item in section]) - - def get_section(self, path): - try: - section = self.get_section_objects(path) - return self.to_block(section) - except ValueError: - return list() - - def get_section_objects(self, path): - if not isinstance(path, list): - path = [path] - obj = self.get_object(path) - if not obj: - raise ValueError('path does not exist in config') - return self.expand_section(obj) - - - def add(self, lines, parents=None): - """Adds one or lines of configuration - """ - - ancestors = list() - offset = 0 - obj = None - - ## global config command - if not parents: - for line in to_list(lines): - item = ConfigLine(line) - item.raw = line - if item not in self.items: - self.items.append(item) - - else: - for index, p in enumerate(parents): - try: - i = index + 1 - obj = self.get_section_objects(parents[:i])[0] - ancestors.append(obj) - - except ValueError: - # add parent to config - offset = index * self.indent - obj = ConfigLine(p) - obj.raw = p.rjust(len(p) + offset) - if ancestors: - obj.parents = list(ancestors) - ancestors[-1].children.append(obj) - self.items.append(obj) - ancestors.append(obj) - - # add child objects - for line in to_list(lines): - # check if child already exists - for child in ancestors[-1].children: - if child.text == line: - break - else: - offset = len(parents) * self.indent - item = ConfigLine(line) - item.raw = line.rjust(len(line) + offset) - item.parents = ancestors - ancestors[-1].children.append(item) - self.items.append(item) - - -def get_network_module(**kwargs): - try: - return get_module(**kwargs) - except NameError: - return NetworkModule(**kwargs) - -def get_config(module, include_defaults=False): - config = module.params['config'] - if not config: - try: - config = module.get_config() - except AttributeError: - defaults = module.params['include_defaults'] - config = module.config.get_config(include_defaults=defaults) - return CustomNetworkConfig(indent=2, contents=config) - -def load_config(module, candidate): - config = get_config(module) - - commands = candidate.difference(config) - commands = [str(c).strip() for c in commands] - - save_config = module.params['save'] - - result = dict(changed=False) - - if commands: - if not module.check_mode: - try: - module.configure(commands) - except AttributeError: - module.config(commands) - - if save_config: - try: - module.config.save_config() - except AttributeError: - module.execute(['copy running-config startup-config']) - - result['changed'] = True - result['updates'] = commands - - return result -# END OF COMMON CODE +from ansible.module_utils.nxos import get_config, load_config, run_commands +from ansible.module_utils.nxos import nxos_argument_spec, check_args +from ansible.module_utils.basic import AnsibleModule +from ansible.module_utils.netcfg import CustomNetworkConfig BOOL_PARAMS = ['suppress_arp'] PARAM_TO_COMMAND_KEYMAP = { @@ -496,9 +347,16 @@ def main(): config=dict(), save=dict(type='bool', default=False) ) - module = get_network_module(argument_spec=argument_spec, + + argument_spec.update(nxos_argument_spec) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + warnings = list() + check_args(module, warnings) + + if module.params['assoc_vrf']: mutually_exclusive_params = ['multicast_group', 'suppress_arp', @@ -587,3 +445,4 @@ def main(): if __name__ == '__main__': main() + diff --git a/lib/ansible/plugins/action/nxos.py b/lib/ansible/plugins/action/nxos.py new file mode 100644 index 0000000000..c6c80a3ad0 --- /dev/null +++ b/lib/ansible/plugins/action/nxos.py @@ -0,0 +1,112 @@ +# +# (c) 2016 Red Hat Inc. +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +import os +import sys +import copy + +from ansible.plugins.action.normal import ActionModule as _ActionModule +from ansible.utils.path import unfrackpath +from ansible.plugins import connection_loader +from ansible.compat.six import iteritems +from ansible.module_utils.nxos import nxos_argument_spec +from ansible.module_utils.basic import AnsibleFallbackNotFound +from ansible.module_utils._text import to_bytes + +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + provider = self.load_provider() + transport = provider['transport'] + + if not transport or 'cli' in transport: + pc = copy.deepcopy(self._play_context) + pc.connection = 'network_cli' + pc.network_os = 'nxos' + pc.port = provider['port'] or self._play_context.port or 22 + pc.remote_user = provider['username'] or self._play_context.connection_user + pc.password = provider['password'] or self._play_context.password + + socket_path = self._get_socket_path(pc) + if not os.path.exists(socket_path): + # start the connection if it isn't started + connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) + connection.exec_command('EXEC: show version') + + task_vars['ansible_socket'] = socket_path + + else: + if provider['host'] is None: + self._task.args['host'] = self._play_context.remote_addr + if provider['username'] is None: + self._task.args['username'] = self._play_context.connection_user + if provider['password'] is None: + self._task.args['password'] = self._play_context.password + if provider['timeout'] is None: + self._task.args['timeout'] = self._play_context.timeout + if task_vars.get('nxapi_use_ssl'): + self._task.args['use_ssl'] = task_vars['nxapi_use_ssl'] + if task_vars.get('nxapi_validate_certs'): + self._task.args['validate_certs'] = task_vars['nxapi_validate_certs'] + + + transport = self._task.args.get('transport') + if not transport: + transport = self._task.args.get('provider', {}).get('transport') + self._task.args['transport'] = transport or 'cli' + + return super(ActionModule, self).run(tmp, task_vars) + + def _get_socket_path(self, play_context): + ssh = connection_loader.get('ssh', class_only=True) + cp = ssh._create_control_path(play_context.remote_addr, play_context.port, play_context.remote_user) + path = unfrackpath("$HOME/.ansible/pc") + return cp % dict(directory=path) + + def load_provider(self): + provider = self._task.args.get('provider', {}) + for key, value in iteritems(nxos_argument_spec): + if key != 'provider' and key not in provider: + if key in self._task.args: + provider[key] = self._task.args[key] + elif 'fallback' in value: + provider[key] = self._fallback(value['fallback']) + elif key not in provider: + provider[key] = None + return provider + + def _fallback(self, fallback): + strategy = fallback[0] + args = [] + kwargs = {} + + for item in fallback[1:]: + if isinstance(item, dict): + kwargs = item + else: + args = item + try: + return strategy(*args, **kwargs) + except AnsibleFallbackNotFound: + pass + + diff --git a/lib/ansible/plugins/action/nxos_config.py b/lib/ansible/plugins/action/nxos_config.py index ffcb0f057f..f3b0e995c4 100644 --- a/lib/ansible/plugins/action/nxos_config.py +++ b/lib/ansible/plugins/action/nxos_config.py @@ -19,10 +19,95 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible.plugins.action import ActionBase -from ansible.plugins.action.net_config import ActionModule as NetActionModule +import os +import re +import time +import glob -class ActionModule(NetActionModule, ActionBase): - pass +from ansible.plugins.action.nxos import ActionModule as _ActionModule +from ansible.module_utils._text import to_text +from ansible.module_utils.six.moves.urllib.parse import urlsplit +from ansible.utils.vars import merge_hash +PRIVATE_KEYS_RE = re.compile('__.+__') + + +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + if self._task.args.get('src'): + try: + self._handle_template() + except ValueError as exc: + return dict(failed=True, msg=exc.message) + + result = super(ActionModule, self).run(tmp, task_vars) + + if self._task.args.get('backup') and result.get('__backup__'): + # User requested backup and no error occurred in module. + # NOTE: If there is a parameter error, _backup key may not be in results. + filepath = self._write_backup(task_vars['inventory_hostname'], + result['__backup__']) + + result['backup_path'] = filepath + + # strip out any keys that have two leading and two trailing + # underscore characters + for key in result.keys(): + if PRIVATE_KEYS_RE.match(key): + del result[key] + + return result + + def _get_working_path(self): + cwd = self._loader.get_basedir() + if self._task._role is not None: + cwd = self._task._role._role_path + return cwd + + def _write_backup(self, host, contents): + backup_path = self._get_working_path() + '/backup' + if not os.path.exists(backup_path): + os.mkdir(backup_path) + for fn in glob.glob('%s/%s*' % (backup_path, host)): + os.remove(fn) + tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time())) + filename = '%s/%s_config.%s' % (backup_path, host, tstamp) + open(filename, 'w').write(contents) + return filename + + def _handle_template(self): + src = self._task.args.get('src') + working_path = self._get_working_path() + + if os.path.isabs(src) or urlsplit('src').scheme: + source = src + else: + source = self._loader.path_dwim_relative(working_path, 'templates', src) + if not source: + source = self._loader.path_dwim_relative(working_path, src) + + if not os.path.exists(source): + raise ValueError('path specified in src not found') + + try: + with open(source, 'r') as f: + template_data = to_text(f.read()) + except IOError: + return dict(failed=True, msg='unable to load src file') + + # Create a template search path in the following order: + # [working_path, self_role_path, dependent_role_paths, dirname(source)] + searchpath = [working_path] + if self._task._role is not None: + searchpath.append(self._task._role._role_path) + if hasattr(self._task, "_block:"): + dep_chain = self._task._block.get_dep_chain() + if dep_chain is not None: + for role in dep_chain: + searchpath.append(role._role_path) + searchpath.append(os.path.dirname(source)) + self._templar.environment.loader.searchpath = searchpath + self._task.args['src'] = self._templar.template(template_data) diff --git a/lib/ansible/plugins/action/nxos_template.py b/lib/ansible/plugins/action/nxos_template.py index 2b63234f16..47f7d55a78 100644 --- a/lib/ansible/plugins/action/nxos_template.py +++ b/lib/ansible/plugins/action/nxos_template.py @@ -19,9 +19,84 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from ansible.plugins.action import ActionBase -from ansible.plugins.action.net_template import ActionModule as NetActionModule +import os +import time +import glob +import urlparse -class ActionModule(NetActionModule, ActionBase): - pass +from ansible.module_utils._text import to_text +from ansible.plugins.action.nxos import ActionModule as _ActionModule +class ActionModule(_ActionModule): + + def run(self, tmp=None, task_vars=None): + + try: + self._handle_template() + except (ValueError, AttributeError) as exc: + return dict(failed=True, msg=exc.message) + + result = super(ActionModule, self).run(tmp, task_vars) + + if self._task.args.get('backup') and result.get('__backup__'): + # User requested backup and no error occurred in module. + # NOTE: If there is a parameter error, __backup__ key may not be in results. + self._write_backup(task_vars['inventory_hostname'], result['__backup__']) + + if '__backup__' in result: + del result['__backup__'] + + return result + + def _get_working_path(self): + cwd = self._loader.get_basedir() + if self._task._role is not None: + cwd = self._task._role._role_path + return cwd + + def _write_backup(self, host, contents): + backup_path = self._get_working_path() + '/backup' + if not os.path.exists(backup_path): + os.mkdir(backup_path) + for fn in glob.glob('%s/%s*' % (backup_path, host)): + os.remove(fn) + tstamp = time.strftime("%Y-%m-%d@%H:%M:%S", time.localtime(time.time())) + filename = '%s/%s_config.%s' % (backup_path, host, tstamp) + open(filename, 'w').write(contents) + + def _handle_template(self): + src = self._task.args.get('src') + if not src: + raise ValueError('missing required arguments: src') + + working_path = self._get_working_path() + + if os.path.isabs(src) or urlparse.urlsplit(src).scheme: + source = src + else: + source = self._loader.path_dwim_relative(working_path, 'templates', src) + if not source: + source = self._loader.path_dwim_relative(working_path, src) + + if not os.path.exists(source): + return + + try: + with open(source, 'r') as f: + template_data = to_text(f.read()) + except IOError: + return dict(failed=True, msg='unable to load src file') + + # Create a template search path in the following order: + # [working_path, self_role_path, dependent_role_paths, dirname(source)] + searchpath = [working_path] + if self._task._role is not None: + searchpath.append(self._task._role._role_path) + if hasattr(self._task, "_block:"): + dep_chain = self._task._block.get_dep_chain() + if dep_chain is not None: + for role in dep_chain: + searchpath.append(role._role_path) + searchpath.append(os.path.dirname(source)) + self._templar.environment.loader.searchpath = searchpath + self._task.args['src'] = self._templar.template(template_data) diff --git a/lib/ansible/plugins/terminal/nxos.py b/lib/ansible/plugins/terminal/nxos.py index e23192f077..21c1e2d680 100644 --- a/lib/ansible/plugins/terminal/nxos.py +++ b/lib/ansible/plugins/terminal/nxos.py @@ -52,11 +52,3 @@ class TerminalModule(TerminalBase): except AnsibleConnectionFailure: raise AnsibleConnectionFailure('unable to set terminal parameters') - @staticmethod - def guess_network_os(conn): - stdin, stdout, stderr = conn.exec_command('show version') - if 'NX-OS' in stdout.read(): - return 'nxos' - - -