1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

refactors nxos module to use persistent connections (#21470)

This completes the refactor of the nxos modules to use the persistent
connection.  It also updates all of the nxos modules to use the
new connection module and preserves use of nxapi as well.
This commit is contained in:
Peter Sprygada 2017-02-15 11:43:09 -05:00 committed by GitHub
parent eb1453a366
commit 21d993a4b8
72 changed files with 2301 additions and 12933 deletions

View file

@ -28,6 +28,7 @@
import re import re
from ansible.module_utils.six.moves import zip from ansible.module_utils.six.moves import zip
from ansible.module_utils.network_common import to_list
DEFAULT_COMMENT_TOKENS = ['#', '!', '/*', '*/'] DEFAULT_COMMENT_TOKENS = ['#', '!', '/*', '*/']
@ -361,3 +362,91 @@ class NetworkConfig(object):
self.items.append(item) 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)

View file

@ -1,80 +1,150 @@
# #
# (c) 2015 Peter Sprygada, <psprygada@ansible.com> # 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 # (c) 2017 Red Hat, Inc.
# 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, # Redistribution and use in source and binary forms, with or without modification,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # are permitted provided that the following conditions are met:
# 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 # * Redistributions of source code must retain the above copyright
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # 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 re
import time
import collections import collections
from ansible.module_utils.basic import json, json_dict_bytes_to_unicode from ansible.module_utils.basic import env_fallback
from ansible.module_utils.network import ModuleStub, NetworkError, NetworkModule from ansible.module_utils.network_common import to_list, ComplexList
from ansible.module_utils.network import add_argument, register_transport, to_list from ansible.module_utils.connection import exec_command
from ansible.module_utils.shell import CliBase from ansible.module_utils.six import iteritems
from ansible.module_utils.urls import fetch_url, url_argument_spec from ansible.module_utils.urls import fetch_url
add_argument('use_ssl', dict(default=False, type='bool')) _DEVICE_CONNECTION = None
add_argument('validate_certs', dict(default=True, type='bool'))
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): 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 = 'show running-config '
if include_defaults: cmd += ' '.join(flags)
cmd += ' all' cmd = cmd.strip()
if isinstance(self, Nxapi):
return self.execute([cmd], output='text')[0] 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: else:
return self.execute([cmd])[0] 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): def load_config(self, config):
checkpoint = 'ansible_%s' % int(time.time()) """Sends configuration commands to the remote device
try: """
self.execute(['checkpoint %s' % checkpoint], output='text') rc, out, err = self.exec_command('configure')
except TypeError: if rc != 0:
self.execute(['checkpoint %s' % checkpoint]) self._module.fail_json(msg='unable to enter configuration mode', output=err)
try: for cmd in config:
self.configure(config) rc, out, err = self.exec_command(cmd)
except NetworkError: if rc != 0:
self.load_checkpoint(checkpoint) self._module.fail_json(msg=err)
raise
try: self.exec_command('end')
self.execute(['no checkpoint %s' % checkpoint], output='text')
except TypeError:
self.execute(['no checkpoint %s' % checkpoint])
def save_config(self, **kwargs): class Nxapi:
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):
OUTPUT_TO_COMMAND_TYPE = { OUTPUT_TO_COMMAND_TYPE = {
'text': 'cli_show_ascii', 'text': 'cli_show_ascii',
@ -83,20 +153,33 @@ class Nxapi(NxapiConfigMixin):
'config': 'cli_conf' 'config': 'cli_conf'
} }
def __init__(self): def __init__(self, module):
self.url = None self._module = module
self.url_args = ModuleStub(url_argument_spec(), self._error)
self._nxapi_auth = None self._nxapi_auth = None
self.default_output = 'json' self._device_configs = {}
self._connected = False
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): def _error(self, msg, **kwargs):
self._nxapi_auth = None self._nxapi_auth = None
if 'url' not in kwargs: if 'url' not in kwargs:
kwargs['url'] = self.url kwargs['url'] = self._url
raise NetworkError(msg, **kwargs) 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 """Encodes a NXAPI JSON request message
""" """
try: try:
@ -120,64 +203,41 @@ class Nxapi(NxapiConfigMixin):
return dict(ins_api=msg) return dict(ins_api=msg)
def connect(self, params, **kwargs): def send_request(self, commands, output='text'):
host = params['host'] # only 10 show commands can be encoded in each request
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
# messages sent to the remote device # messages sent to the remote device
if output != 'config':
commands = collections.deque(commands)
stack = list() stack = list()
requests = list() requests = list()
while commands: while commands:
stack.append(commands.popleft()) stack.append(commands.popleft())
if len(stack) == 10: if len(stack) == 10:
body = self._get_body(stack, output) body = self._request_builder(stack, output)
data = self._jsonify(body) data = self._module.jsonify(body)
requests.append(data) requests.append(data)
stack = list() stack = list()
if stack: if stack:
body = self._get_body(stack, output) body = self._request_builder(stack, output)
data = self._jsonify(body) data = self._module.jsonify(body)
requests.append(data) requests.append(data)
else:
requests = commands
headers = {'Content-Type': 'application/json'} headers = {'Content-Type': 'application/json'}
result = list() result = list()
timeout = self.url_args.params['timeout'] timeout = self._module.params['timeout'] or 10
for req in requests: for req in requests:
if self._nxapi_auth: if self._nxapi_auth:
headers['Cookie'] = self._nxapi_auth headers['Cookie'] = self._nxapi_auth
response, headers = fetch_url( 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') self._nxapi_auth = headers.get('set-cookie')
@ -185,9 +245,9 @@ class Nxapi(NxapiConfigMixin):
self._error(**headers) self._error(**headers)
try: try:
response = json.loads(response.read()) response = self._module.from_json(response.read())
except ValueError: 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'] output = response['ins_api']['outputs']['output']
for item in to_list(output): for item in to_list(output):
@ -198,115 +258,96 @@ class Nxapi(NxapiConfigMixin):
return result 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 output = None
cmds = list() queue = list()
responses = list() responses = list()
for cmd in commands: _send = lambda commands, output: self.send_request(commands, output)
if output and output != cmd.output:
responses.extend(self.execute(cmds, output=output))
cmds = list()
output = cmd.output for item in to_list(commands):
cmds.append(str(cmd)) if is_json(item['command']):
item['command'] = str(item['command']).split('|')[0]
item['output'] = 'json'
if cmds: if all((output == 'json', item['output'] == 'text')) or all((output =='text', item['output'] == 'json')):
responses.extend(self.execute(cmds, output=output)) 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 return responses
def load_config(self, config):
### Config methods ### """Sends the ordered set of commands to the device
"""
def configure(self, commands): cmds = ['configure terminal']
commands = to_list(commands) cmds.extend(commands)
return self.execute(commands, output='config') self.send_request(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)
class Cli(NxapiConfigMixin, CliBase): is_json = lambda x: str(x).endswith('| json')
is_text = lambda x: not is_json
CLI_PROMPTS_RE = [ def is_nxapi(module):
re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*[>|#|%](?:\s*)$'), transport = module.params['transport']
re.compile(r'[\r\n]?[a-zA-Z]{1}[a-zA-Z0-9-]*\(.+\)#(?:\s*)$') provider_transport = (module.params['provider'] or {}).get('transport')
] return 'nxapi' in (transport, provider_transport)
CLI_ERRORS_RE = [ def to_command(module, commands):
re.compile(r"% ?Error"), if is_nxapi(module):
re.compile(r"^% \w+", re.M), default_output = 'json'
re.compile(r"% ?Bad secret"), else:
re.compile(r"invalid input", re.I), default_output = 'text'
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) transform = ComplexList(dict(
command=dict(key=True),
output=dict(default=default_output),
prompt=dict(),
response=dict()
), module)
def connect(self, params, **kwargs): commands = transform(to_list(commands))
super(Cli, self).connect(params, kickstart=False, **kwargs)
self.shell.send('terminal length 0')
### 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): def get_config(module, flags=[]):
cmds = list(prepare_commands(commands)) conn = get_connection(module)
responses = self.execute(cmds) return conn.get_config(flags)
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
### 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): def load_config(module, config):
commands = prepare_config(commands) conn = get_connection(module)
responses = self.execute(commands) return conn.load_config(config)
responses.pop(0)
return responses
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

View file

@ -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')

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages AAA server global configuration. short_description: Manages AAA server global configuration.
description: description:
- Manages AAA server global configuration - Manages AAA server global configuration
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: notes:
@ -155,220 +154,19 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import json
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
cmds = [command] cmds = [command]
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -490,9 +288,16 @@ def main():
choices=['enabled', 'disabled', 'default']), choices=['enabled', 'disabled', 'default']),
state=dict(choices=['default', 'present'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
server_type = module.params['server_type'] server_type = module.params['server_type']
global_key = module.params['global_key'] global_key = module.params['global_key']
encrypt_type = module.params['encrypt_type'] encrypt_type = module.params['encrypt_type']
@ -555,7 +360,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_aaa_server_info(server_type, module) end_state = get_aaa_server_info(server_type, module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -565,6 +370,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -572,3 +378,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages AAA server host-specific configuration. short_description: Manages AAA server host-specific configuration.
description: description:
- Manages AAA server host-specific configuration. - Manages AAA server host-specific configuration.
extends_documentation_fragment: nxos
author: Jason Edelman (@jedelman8) author: Jason Edelman (@jedelman8)
notes: notes:
- Changes to the AAA server host key (shared secret) are not idempotent. - Changes to the AAA server host key (shared secret) are not idempotent.
@ -150,236 +149,11 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import json
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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
def execute_show_command(command, module, command_type='cli_show'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -495,9 +268,16 @@ def main():
tacacs_port=dict(type='str'), tacacs_port=dict(type='str'),
state=dict(choices=['absent', 'present'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
server_type = module.params['server_type'] server_type = module.params['server_type']
address = module.params['address'] address = module.params['address']
key = module.params['key'] key = module.params['key']
@ -565,7 +345,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_aaa_host_info(module, server_type, address) end_state = get_aaa_host_info(module, server_type, address)
results = {} results = {}
@ -573,6 +353,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -580,3 +361,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages access list entries for ACLs. short_description: Manages access list entries for ACLs.
description: description:
- Manages access list entries for ACLs. - Manages access list entries for ACLs.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -241,227 +240,21 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import collections
import json
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -621,24 +414,6 @@ def flatten_list(command_lists):
return flat_command_list 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(): def main():
argument_spec = dict( argument_spec = dict(
seq=dict(required=False, type='str'), seq=dict(required=False, type='str'),
@ -685,9 +460,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
action = module.params['action'] action = module.params['action']
remark = module.params['remark'] remark = module.params['remark']
@ -797,7 +579,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
new_existing_core, end_state, seqs = get_acl(module, name, seq) new_existing_core, end_state, seqs = get_acl(module, name, seq)
if 'configure' in cmds: if 'configure' in cmds:
@ -806,6 +588,7 @@ def main():
results['proposed'] = proposed results['proposed'] = proposed
results['existing'] = existing_core results['existing'] = existing_core
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['updates'] = cmds results['updates'] = cmds
results['end_state'] = end_state results['end_state'] = end_state
@ -814,3 +597,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages applying ACLs to interfaces. short_description: Manages applying ACLs to interfaces.
description: description:
- Manages applying ACLs to interfaces. - Manages applying ACLs to interfaces.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -99,216 +98,11 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import collections
import json
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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
def execute_show_command(command, module, command_type='cli_show'): 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: if 'summary' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -446,24 +239,6 @@ def flatten_list(command_lists):
return flat_command_list 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(): def main():
argument_spec = dict( argument_spec = dict(
name=dict(required=False, type='str'), name=dict(required=False, type='str'),
@ -475,9 +250,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
name = module.params['name'] name = module.params['name']
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
@ -517,7 +299,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state_acls = get_acl_interface(module, name) end_state_acls = get_acl_interface(module, name)
interfaces_acls, this_dir_acl_intf = other_existing_acl( interfaces_acls, this_dir_acl_intf = other_existing_acl(
@ -533,6 +315,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
results['acl_applied_to'] = end_state_acls results['acl_applied_to'] = end_state_acls
@ -541,3 +324,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -30,7 +30,6 @@ description:
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- C(state=absent) removes the whole BGP ASN configuration when - C(state=absent) removes the whole BGP ASN configuration when
C(vrf=default) or the whole VRF instance within the BGP process when C(vrf=default) or the whole VRF instance within the BGP process when
@ -361,156 +360,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
WARNINGS = [] WARNINGS = []
@ -902,11 +756,18 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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', required_together=[['timer_bgp_hold',
'timer_bgp_keepalive']], 'timer_bgp_keepalive']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
args = [ args = [
"asn", "asn",
@ -1010,3 +871,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages BGP Address-family configuration.
description: description:
- Manages BGP Address-family configurations on NX-OS switches. - Manages BGP Address-family configurations on NX-OS switches.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- C(state=absent) removes the whole BGP ASN configuration - C(state=absent) removes the whole BGP ASN configuration
- Default, where supported, restores params default value. - Default, where supported, restores params default value.
@ -300,157 +299,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
WARNINGS = [] WARNINGS = []
BOOL_PARAMS = [ BOOL_PARAMS = [
@ -992,13 +845,20 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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, required_together=[DAMPENING_PARAMS,
['distance_ibgp', ['distance_ibgp',
'distance_ebgp', 'distance_ebgp',
'distance_local']], 'distance_local']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
if module.params['dampening_routemap']: if module.params['dampening_routemap']:
for param in DAMPENING_PARAMS: for param in DAMPENING_PARAMS:
@ -1108,3 +968,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages BGP neighbors configurations.
description: description:
- Manages BGP neighbors configurations on NX-OS switches. - Manages BGP neighbors configurations on NX-OS switches.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- C(state=absent) removes the whole BGP neighbor configuration. - C(state=absent) removes the whole BGP neighbor configuration.
- Default, where supported, restores params default value. - Default, where supported, restores params default value.
@ -245,156 +244,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
WARNINGS = [] WARNINGS = []
@ -682,11 +536,18 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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', required_together=[['timer_bgp_hold',
'timer_bgp_keepalive']], 'timer_bgp_keepalive']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
if module.params['pwd_type'] == 'default': if module.params['pwd_type'] == 'default':
module.params['pwd_type'] = '0' module.params['pwd_type'] = '0'
@ -767,3 +628,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages BGP address-family's neighbors configuration.
description: description:
- Manages BGP address-family's neighbors configurations on NX-OS switches. - Manages BGP address-family's neighbors configurations on NX-OS switches.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- C(state=absent) removes the whole BGP address-family's - C(state=absent) removes the whole BGP address-family's
neighbor configuration. neighbor configuration.
@ -322,156 +321,11 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
WARNINGS = [] WARNINGS = []
BOOL_PARAMS = [ BOOL_PARAMS = [
@ -1004,11 +858,18 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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', mutually_exclusive=[['advertise_map_exist',
'advertise_map_non_exist']], 'advertise_map_non_exist']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
if ((module.params['max_prefix_interval'] or if ((module.params['max_prefix_interval'] or
module.params['max_prefix_warning'] or module.params['max_prefix_warning'] or
@ -1120,3 +981,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -16,9 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
ANSIBLE_METADATA = {'status': ['preview'], ANSIBLE_METADATA = {
'status': ['preview'],
'supported_by': 'core', 'supported_by': 'core',
'version': '1.0'} 'version': '1.0'
}
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
@ -31,7 +33,6 @@ description:
read from the device. This module includes an read from the device. This module includes an
argument that will cause the module to wait for a specific condition argument that will cause the module to wait for a specific condition
before returning or timing out if the condition is not met. before returning or timing out if the condition is not met.
extends_documentation_fragment: nxos
options: options:
commands: commands:
description: description:
@ -152,37 +153,53 @@ failed_conditions:
type: list type: list
sample: ['...', '...'] sample: ['...', '...']
""" """
import ansible.module_utils.nxos import time
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import run_commands
from ansible.module_utils.network import NetworkModule, NetworkError from ansible.module_utils.pycompat24 import get_exception
from ansible.module_utils.netcli import CommandRunner from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcli import FailedConditionsError from ansible.module_utils.six import string_types
from ansible.module_utils.netcli import FailedConditionalError from ansible.module_utils.netcli import Conditional
from ansible.module_utils.netcli import AddCommandError, AddConditionError from ansible.module_utils.network_common import ComplexList
from ansible.module_utils.nxos import nxos_argument_spec, check_args
VALID_KEYS = ['command', 'output', 'prompt', 'response']
def to_lines(stdout): def to_lines(stdout):
lines = list()
for item in stdout: for item in stdout:
if isinstance(item, basestring): if isinstance(item, basestring):
item = str(item).split('\n') item = str(item).split('\n')
yield item lines.append(item)
return lines
def parse_commands(module): def parse_commands(module, warnings):
for cmd in module.params['commands']: transform = ComplexList(dict(
if isinstance(cmd, basestring): command=dict(key=True),
cmd = dict(command=cmd, output=None) output=dict(),
elif 'command' not in cmd: prompt=dict(),
module.fail_json(msg='command keyword argument is required') response=dict()
elif cmd.get('output') not in [None, 'text', 'json']: ), module)
module.fail_json(msg='invalid output specified for command')
elif not set(cmd.keys()).issubset(VALID_KEYS): commands = transform(module.params['commands'])
module.fail_json(msg='unknown keyword specified')
yield cmd 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(): def main():
spec = dict( """entry point for module execution
"""
argument_spec = dict(
# { command: <str>, output: <str>, prompt: <str>, response: <str> } # { command: <str>, output: <str>, prompt: <str>, response: <str> }
commands=dict(type='list', required=True), commands=dict(type='list', required=True),
@ -193,66 +210,56 @@ def main():
interval=dict(default=1, type='int') 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) supports_check_mode=True)
commands = list(parse_commands(module))
conditionals = module.params['wait_for'] or list() result = {'changed': False}
warnings = list() warnings = list()
check_args(module, warnings)
runner = CommandRunner(module) commands = parse_commands(module, warnings)
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)
result['warnings'] = 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) module.exit_json(**result)

View file

@ -16,9 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
ANSIBLE_METADATA = {'status': ['preview'], ANSIBLE_METADATA = {
'status': ['preview'],
'supported_by': 'core', 'supported_by': 'core',
'version': '1.0'} 'version': '1.0'
}
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
@ -32,7 +34,6 @@ description:
an implementation for working with NXOS configuration sections in an implementation for working with NXOS configuration sections in
a deterministic way. This module works with either CLI or NXAPI a deterministic way. This module works with either CLI or NXAPI
transports. transports.
extends_documentation_fragment: nxos
options: options:
lines: lines:
description: description:
@ -212,18 +213,28 @@ backup_path:
type: path type: path
sample: /playbooks/ansible/backup/nxos_config.2016-07-16@22:28:34 sample: /playbooks/ansible/backup/nxos_config.2016-07-16@22:28:34
""" """
from ansible.module_utils.basic import AnsibleModule
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.netcfg import NetworkConfig, dumps 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): def check_args(module, warnings):
nxos_check_args(module, warnings)
if module.params['force']: if module.params['force']:
warnings.append('The force argument is deprecated, please use ' warnings.append('The force argument is deprecated, please use '
'match=none instead. This argument will be ' 'match=none instead. This argument will be '
'removed in the future') '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): def get_candidate(module):
candidate = NetworkConfig(indent=2) candidate = NetworkConfig(indent=2)
if module.params['src']: if module.params['src']:
@ -233,13 +244,6 @@ def get_candidate(module):
candidate.add(module.params['lines'], parents=parents) candidate.add(module.params['lines'], parents=parents)
return candidate 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): def run(module, result):
match = module.params['match'] match = module.params['match']
replace = module.params['replace'] replace = module.params['replace']
@ -247,10 +251,9 @@ def run(module, result):
candidate = get_candidate(module) candidate = get_candidate(module)
if match != 'none': if match != 'none':
config = get_config(module) config = get_running_config(module)
path = module.params['parents'] path = module.params['parents']
configobjs = candidate.difference(config, path=path, match=match, configobjs = candidate.difference(config, match=match, replace=replace, path=path)
replace=replace)
else: else:
configobjs = candidate.items configobjs = candidate.items
@ -264,22 +267,17 @@ def run(module, result):
if module.params['after']: if module.params['after']:
commands.extend(module.params['after']) commands.extend(module.params['after'])
result['commands'] = commands
result['updates'] = commands result['updates'] = commands
if not module.check_mode: if not module.check_mode:
module.config.load_config(commands) load_config(module, commands)
result['changed'] = True result['changed'] = True
if module.params['save']:
if not module.check_mode:
module.config.save_config()
result['changed'] = True
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( argument_spec = dict(
src=dict(type='path'), src=dict(type='path'),
@ -303,14 +301,15 @@ def main():
save=dict(type='bool', default=False), save=dict(type='bool', default=False),
) )
argument_spec.update(nxos_argument_spec)
mutually_exclusive = [('lines', 'src')] mutually_exclusive = [('lines', 'src')]
required_if = [('match', 'strict', ['lines']), required_if = [('match', 'strict', ['lines']),
('match', 'exact', ['lines']), ('match', 'exact', ['lines']),
('replace', 'block', ['lines'])] ('replace', 'block', ['lines'])]
module = NetworkModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
connect_on_load=False,
mutually_exclusive=mutually_exclusive, mutually_exclusive=mutually_exclusive,
required_if=required_if, required_if=required_if,
supports_check_mode=True) supports_check_mode=True)
@ -326,11 +325,13 @@ def main():
if module.params['backup']: if module.params['backup']:
result['__backup__'] = module.config.get_config() result['__backup__'] = module.config.get_config()
try: if any((module.params['src'], module.params['lines'])):
run(module, result) run(module, result)
except NetworkError:
exc = get_exception() if module.params['save']:
module.fail_json(msg=str(exc), **exc.kwargs) if not module.check_mode:
run_commands(module, ['copy running-config startup-config'])
result['changed'] = True
module.exit_json(**result) module.exit_json(**result)

View file

@ -28,7 +28,6 @@ short_description: Handles the EVPN control plane for VXLAN.
description: description:
- Handles the EVPN control plane for VXLAN. - Handles the EVPN control plane for VXLAN.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
options: options:
nv_overlay_evpn: nv_overlay_evpn:
description: description:
@ -73,156 +72,11 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'nv_overlay_evpn': 'nv overlay evpn', 'nv_overlay_evpn': 'nv overlay evpn',
@ -286,9 +140,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
existing = invoke('get_existing', module) existing = invoke('get_existing', module)
end_state = existing end_state = existing
proposed = dict(nv_overlay_evpn=module.params['nv_overlay_evpn']) proposed = dict(nv_overlay_evpn=module.params['nv_overlay_evpn'])
@ -314,8 +175,11 @@ def main():
result['existing'] = existing result['existing'] = existing
result['proposed'] = proposed result['proposed'] = proposed
result['warnings'] = warnings
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Manages Cisco Ethernet Virtual Private Network (EVPN) VXLAN Network - Manages Cisco Ethernet Virtual Private Network (EVPN) VXLAN Network
Identifier (VNI) configurations of a Nexus device. Identifier (VNI) configurations of a Nexus device.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- default, where supported, restores params default value. - default, where supported, restores params default value.
- RD override is not permitted. You should set it to the default values - RD override is not permitted. You should set it to the default values
@ -127,156 +126,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'vni': 'vni', 'vni': 'vni',
@ -420,9 +274,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
args = [ args = [
'vni', 'vni',
@ -490,3 +351,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -176,31 +176,24 @@ vlan_list:
""" """
import re import re
import ansible.module_utils.nxos from ansible.module_utils.nxos import run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcli import CommandRunner, AddCommandError from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network import NetworkModule, NetworkError from ansible.module_utils.network_common import exec_command
from ansible.module_utils.six import iteritems 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): class FactsBase(object):
def __init__(self, module, runner): COMMANDS = frozenset()
self.module = module
self.runner = runner
self.facts = dict()
self.commands()
def commands(self): def __init__(self, module):
raise NotImplementedError 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): def transform_dict(self, data, keymap):
transform = dict() transform = dict()
@ -224,33 +217,36 @@ class Default(FactsBase):
('host_name', 'hostname') ('host_name', 'hostname')
]) ])
def commands(self): COMMANDS = ['show version | json']
add_command(self.runner, 'show version', output='json')
def populate(self): 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)) self.facts.update(self.transform_dict(data, self.VERSION_MAP))
class Config(FactsBase): class Config(FactsBase):
def commands(self): COMMANDS = ['show running-config']
add_command(self.runner, 'show running-config')
def populate(self): 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): class Hardware(FactsBase):
def commands(self): COMMANDS = [
add_command(self.runner, 'dir', output='text') 'dir',
add_command(self.runner, 'show system resources', output='json') 'show system resources | json'
]
def populate(self): 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) 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['memtotal_mb'] = int(data['memory_usage_total']) / 1024
self.facts['memfree_mb'] = int(data['memory_usage_free']) / 1024 self.facts['memfree_mb'] = int(data['memory_usage_free']) / 1024
@ -282,38 +278,21 @@ class Interfaces(FactsBase):
('prefix', 'subnet') ('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): def populate(self):
self.facts['all_ipv4_addresses'] = list() self.facts['all_ipv4_addresses'] = list()
self.facts['all_ipv6_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) self.facts['interfaces'] = self.populate_interfaces(data)
if self.ipv6: rc, out, err = exec_command(self.module, 'show ipv6 interface | json')
data = self.runner.get_command('show ipv6 interface', 'json') if rc == 0:
if data: if out:
self.parse_ipv6_interfaces(data) self.parse_ipv6_interfaces(out)
if self.lldp_enabled: rc, out, err = exec_command(self.module, 'show lldp neighbors')
data = self.runner.get_command('show lldp neighbors', 'json') if rc == 0:
self.facts['neighbors'] = self.populate_neighbors(data) self.facts['neighbors'] = self.populate_neighbors(out)
def populate_interfaces(self, data): def populate_interfaces(self, data):
interfaces = dict() interfaces = dict()
@ -390,27 +369,30 @@ class Legacy(FactsBase):
('total_capa', 'total_capacity') ('total_capa', 'total_capacity')
]) ])
def commands(self): COMMANDS = [
add_command(self.runner, 'show version', output='json') 'show version | json',
add_command(self.runner, 'show module', output='json') 'show module | json',
add_command(self.runner, 'show environment', output='json') 'show environment | json',
add_command(self.runner, 'show interface', output='json') 'show interface | json',
add_command(self.runner, 'show vlan brief', output='json') 'show vlan brief | json'
]
def populate(self): 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)) 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) 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) 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) 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['_fan_info'] = self.parse_fan_info(data)
self.facts['_power_supply_info'] = self.parse_power_supply_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') 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'] gather_subset = module.params['gather_subset']
@ -501,25 +488,13 @@ def main():
facts = dict() facts = dict()
facts['gather_subset'] = list(runable_subsets) facts['gather_subset'] = list(runable_subsets)
runner = CommandRunner(module)
instances = list() instances = list()
for key in runable_subsets: 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: for inst in instances:
inst.populate() inst.populate()
facts.update(inst.facts) facts.update(inst.facts)
except Exception:
raise
module.exit_json(out=module.from_json(runner.items))
ansible_facts = dict() ansible_facts = dict()
for key, value in iteritems(facts): for key, value in iteritems(facts):
@ -530,7 +505,7 @@ def main():
key = 'ansible_net_%s' % key key = 'ansible_net_%s' % key
ansible_facts[key] = value ansible_facts[key] = value
module.exit_json(ansible_facts=ansible_facts) module.exit_json(ansible_facts=ansible_facts, warnings=warnings)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -27,7 +27,6 @@ version_added: "2.1"
short_description: Manage features in NX-OS switches. short_description: Manage features in NX-OS switches.
description: description:
- Offers ability to enable and disable features in NX-OS. - Offers ability to enable and disable features in NX-OS.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -97,244 +96,11 @@ feature:
type: string type: string
sample: "vpc" sample: "vpc"
''' '''
import json
import collections
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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
def apply_key_map(key_map, table): def apply_key_map(key_map, table):
new_dict = {} new_dict = {}
@ -354,7 +120,8 @@ def get_available_features(feature, module):
feature_regex = '(?P<feature>\S+)\s+\d+\s+(?P<state>.*)' feature_regex = '(?P<feature>\S+)\s+\d+\s+(?P<state>.*)'
command = 'show feature' 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() split_body = body[0].splitlines()
for line in split_body: for line in split_body:
@ -451,9 +218,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
feature = validate_feature(module) feature = validate_feature(module)
state = module.params['state'].lower() state = module.params['state'].lower()
@ -477,7 +251,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
updated_features = get_available_features(feature, module) updated_features = get_available_features(feature, module)
existstate = updated_features[feature] existstate = updated_features[feature]
@ -491,6 +265,7 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['feature'] = module.params['feature'] results['feature'] = module.params['feature']
module.exit_json(**results) module.exit_json(**results)
@ -498,3 +273,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -31,7 +31,6 @@ description:
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- The feature must be enabled with feature scp-server. - The feature must be enabled with feature scp-server.
- If the file is already present (md5 sums match), no transfer will - If the file is already present (md5 sums match), no transfer will
@ -82,205 +81,29 @@ remote_file:
type: string type: string
sample: '/path/to/remote/file' sample: '/path/to/remote/file'
''' '''
import os import os
from scp import SCPClient import re
import paramiko
import time import time
# COMMON CODE FOR MIGRATION import paramiko
import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
try: try:
from ansible.module_utils.nxos import get_module from scp import SCPClient
HAS_SCP = True
except ImportError: except ImportError:
from ansible.module_utils.nxos import NetworkModule HAS_SCP = False
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
cmds = [command] cmds = [command]
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -372,9 +195,21 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) 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'] local_file = module.params['local_file']
remote_file = module.params['remote_file'] remote_file = module.params['remote_file']
file_system = module.params['file_system'] file_system = module.params['file_system']
@ -409,8 +244,10 @@ def main():
transfer_status=transfer_status, transfer_status=transfer_status,
local_file=local_file, local_file=local_file,
remote_file=remote_file, remote_file=remote_file,
warnings=warnings,
file_system=file_system) file_system=file_system)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Trigger a graceful removal or insertion (GIR) of the switch. short_description: Trigger a graceful removal or insertion (GIR) of the switch.
description: description:
- Trigger a graceful removal or insertion (GIR) of the switch. - Trigger a graceful removal or insertion (GIR) of the switch.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -161,220 +160,22 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
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_ascii'): def execute_show_command(command, module, command_type='cli_show_ascii'):
cmds = [command] cmds = [command]
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body 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): def get_system_mode(module):
command = 'show system mode' command = 'show system mode'
body = execute_show_command(command, module)[0] body = execute_show_command(command, module)[0]
@ -468,7 +269,10 @@ def main():
state=dict(choices=['absent', 'present', 'default'], state=dict(choices=['absent', 'present', 'default'],
default='present', required=False) 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=[[ mutually_exclusive=[[
'system_mode_maintenance', 'system_mode_maintenance',
'system_mode_maintenance_dont_generate_profile', 'system_mode_maintenance_dont_generate_profile',
@ -485,6 +289,10 @@ def main():
]], ]],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
mode = get_system_mode(module) mode = get_system_mode(module)
commands = get_commands(module, state, mode) commands = get_commands(module, state, mode)
@ -493,7 +301,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=commands) module.exit_json(changed=True, commands=commands)
else: else:
execute_config_command(commands, module) load_config(module, commands)
changed = True changed = True
result = {} result = {}
@ -504,8 +312,11 @@ def main():
result['final_system_mode'] = final_system_mode result['final_system_mode'] = final_system_mode
result['updates'] = commands result['updates'] = commands
result['warnings'] = warnings
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Manage a maintenance-mode or normal-mode profile with configuration - Manage a maintenance-mode or normal-mode profile with configuration
commands that can be applied during graceful removal commands that can be applied during graceful removal
or graceful insertion. or graceful insertion.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -117,159 +116,11 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
def get_existing(module): def get_existing(module):
@ -315,24 +166,6 @@ def invoke(name, *args, **kwargs):
return func(*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(): def main():
argument_spec = dict( argument_spec = dict(
commands=dict(required=False, type='list'), commands=dict(required=False, type='list'),
@ -342,9 +175,16 @@ def main():
include_defaults=dict(default=False), include_defaults=dict(default=False),
config=dict() 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
commands = module.params['commands'] or [] commands = module.params['commands'] or []
@ -363,7 +203,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state = invoke('get_existing', module) end_state = invoke('get_existing', module)
@ -376,8 +216,11 @@ def main():
result['proposed'] = commands result['proposed'] = commands
result['updates'] = cmds result['updates'] = cmds
result['warnings'] = warnings
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages HSRP configuration on NX-OS switches. short_description: Manages HSRP configuration on NX-OS switches.
description: description:
- Manages HSRP configuration on NX-OS switches. - Manages HSRP configuration on NX-OS switches.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -143,239 +142,21 @@ changed:
sample: true 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -619,9 +400,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
group = module.params['group'] group = module.params['group']
version = module.params['version'] version = module.params['version']
@ -699,7 +487,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=commands) module.exit_json(changed=True, commands=commands)
else: else:
body = execute_config_command(commands, module) load_config(module, commands)
if transport == 'cli': if transport == 'cli':
validate_config(body, vip, module) validate_config(body, vip, module)
changed = True changed = True
@ -713,9 +501,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = commands results['updates'] = commands
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages IGMP global configuration. short_description: Manages IGMP global configuration.
description: description:
- Manages IGMP global configuration configuration settings. - Manages IGMP global configuration configuration settings.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -110,159 +109,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'flush_routes': 'ip igmp flush-routes', 'flush_routes': 'ip igmp flush-routes',
@ -343,9 +194,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
restart = module.params['restart'] restart = module.params['restart']
@ -392,8 +250,11 @@ def main():
result['existing'] = existing result['existing'] = existing
result['proposed'] = proposed result['proposed'] = proposed
result['warnings'] = warnings
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages IGMP interface configuration. short_description: Manages IGMP interface configuration.
description: description:
- Manages IGMP interface configuration settings. - Manages IGMP interface configuration settings.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -233,225 +232,21 @@ changed:
sample: true sample: true
''' '''
import json from ansible.module_utils.nxos import get_config, load_config, run_commands
import collections 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -712,24 +507,6 @@ def config_remove_oif(existing, existing_oif_prefix_source):
return commands 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(): def main():
argument_spec = dict( argument_spec = dict(
interface=dict(required=True, type='str'), interface=dict(required=True, type='str'),
@ -755,9 +532,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
interface = module.params['interface'] interface = module.params['interface']
oif_prefix = module.params['oif_prefix'] oif_prefix = module.params['oif_prefix']
@ -891,7 +675,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state = get_igmp_interface(module, interface) end_state = get_igmp_interface(module, interface)
if 'configure' in cmds: if 'configure' in cmds:
@ -901,6 +685,7 @@ def main():
results['existing'] = existing_copy results['existing'] = existing_copy
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -908,3 +693,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -30,7 +30,6 @@ description:
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- When C(state=default), params will be reset to a default state. - When C(state=default), params will be reset to a default state.
- C(group_timeout) also accepts I(never) as an input. - C(group_timeout) also accepts I(never) as an input.
@ -129,229 +128,23 @@ changed:
sample: true 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -366,24 +159,6 @@ def flatten_list(command_lists):
return flat_command_list 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): def get_group_timeout(config):
command = 'ip igmp snooping group-timeout' command = 'ip igmp snooping group-timeout'
REGEX = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(command), re.M) REGEX = re.compile(r'(?:{0}\s)(?P<value>.*)$'.format(command), re.M)
@ -492,9 +267,16 @@ def main():
v3_report_supp=dict(required=False, type='bool'), v3_report_supp=dict(required=False, type='bool'),
state=dict(choices=['present', 'default'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
snooping = module.params['snooping'] snooping = module.params['snooping']
link_local_grp_supp = module.params['link_local_grp_supp'] link_local_grp_supp = module.params['link_local_grp_supp']
report_supp = module.params['report_supp'] report_supp = module.params['report_supp']
@ -539,7 +321,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_igmp_snooping(module) end_state = get_igmp_snooping(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -548,9 +330,11 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -115,220 +115,23 @@ install_state:
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
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_ascii'): def execute_show_command(command, module, command_type='cli_show_ascii'):
cmds = [command] cmds = [command]
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body 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): def get_boot_options(module):
"""Get current boot variables """Get current boot variables
like system image and kickstart image. like system image and kickstart image.
@ -376,7 +179,7 @@ def set_boot_options(module, image_name, kickstart=None):
else: else:
commands.append( commands.append(
'install all system %s kickstart %s' % (image_name, kickstart)) 'install all system %s kickstart %s' % (image_name, kickstart))
execute_config_command(commands, module) load_config(module, commands)
def main(): def main():
@ -384,9 +187,16 @@ def main():
system_image_file=dict(required=True), system_image_file=dict(required=True),
kickstart_image_file=dict(required=False), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
system_image_file = module.params['system_image_file'] system_image_file = module.params['system_image_file']
kickstart_image_file = module.params['kickstart_image_file'] kickstart_image_file = module.params['kickstart_image_file']
@ -413,8 +223,9 @@ def main():
else: else:
install_state = current_boot_options 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__': if __name__ == '__main__':
main() main()

View file

@ -162,157 +162,12 @@ changed:
sample: true 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
# COMMON CODE FOR MIGRATION 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
def is_default_interface(interface, module): def is_default_interface(interface, module):
@ -710,95 +565,23 @@ def smart_existing(module, intf_type, normalized_interface):
return existing, is_default 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [{'command': command, 'output': 'json'}]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
def execute_modified_show_for_cli_text(command, module): def execute_modified_show_for_cli_text(command, module):
cmds = [command] cmds = [command]
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
response = execute_show(cmds, module) body = run_commands(module, cmds)
else: else:
response = execute_show(cmds, module, command_type='cli_show_ascii') body = run_commands(module, cmds)
body = response body = response
return body return body
@ -840,10 +623,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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']], mutually_exclusive=[['interface', 'interface_type']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
interface = module.params['interface'] interface = module.params['interface']
interface_type = module.params['interface_type'] interface_type = module.params['interface_type']
admin_state = module.params['admin_state'] admin_state = module.params['admin_state']
@ -937,7 +726,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
if module.params['interface']: if module.params['interface']:
if delta.get('mode'): # or delta.get('admin_state'): if delta.get('mode'): # or delta.get('admin_state'):
@ -948,7 +737,7 @@ def main():
c1 = 'interface {0}'.format(normalized_interface) c1 = 'interface {0}'.format(normalized_interface)
c2 = get_admin_state(delta, normalized_interface, admin_state) c2 = get_admin_state(delta, normalized_interface, admin_state)
cmds2 = [c1, c2] cmds2 = [c1, c2]
execute_config_command(cmds2, module) load_config(module, cmds2)
cmds.extend(cmds2) cmds.extend(cmds2)
end_state, is_default = smart_existing(module, intf_type, end_state, is_default = smart_existing(module, intf_type,
normalized_interface) normalized_interface)
@ -962,9 +751,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages configuration of an OSPF interface instance.
description: description:
- Manages configuration of an OSPF interface instance. - Manages configuration of an OSPF interface instance.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- Default, where supported, restores params default value. - Default, where supported, restores params default value.
- To remove an existing authentication configuration you should use - To remove an existing authentication configuration you should use
@ -167,156 +166,11 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
import ansible.module_utils.nxos from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import get_exception from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.netcfg import CustomNetworkConfig
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
BOOL_PARAMS = [ BOOL_PARAMS = [
'passive_interface', 'passive_interface',
@ -597,7 +451,10 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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', required_together=[['message_digest_key_id',
'message_digest_algorithm_type', 'message_digest_algorithm_type',
'message_digest_encryption_type', 'message_digest_encryption_type',
@ -607,6 +464,9 @@ def main():
if not module.params['interface'].startswith('loopback'): if not module.params['interface'].startswith('loopback'):
module.params['interface'] = module.params['interface'].capitalize() module.params['interface'] = module.params['interface'].capitalize()
warnings = list()
check_args(module, warnings)
for param in ['message_digest_encryption_type', for param in ['message_digest_encryption_type',
'message_digest_algorithm_type', 'message_digest_algorithm_type',
'message_digest_password']: 'message_digest_password']:
@ -674,8 +534,11 @@ def main():
result['existing'] = existing result['existing'] = existing
result['proposed'] = proposed_args result['proposed'] = proposed_args
result['warnings'] = warnings
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.1"
short_description: Manages L3 attributes for IPv4 and IPv6 interfaces. short_description: Manages L3 attributes for IPv4 and IPv6 interfaces.
description: description:
- Manages Layer 3 attributes for IPv4 and IPv6 interfaces. - Manages Layer 3 attributes for IPv4 and IPv6 interfaces.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -111,242 +110,21 @@ changed:
sample: true sample: true
''' '''
import json from ansible.module_utils.nxos import get_config, load_config, run_commands
import collections 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -640,9 +418,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
addr = module.params['addr'] addr = module.params['addr']
version = module.params['version'] version = module.params['version']
mask = module.params['mask'] mask = module.params['mask']
@ -702,7 +487,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state, address_list = get_ip_interface(interface, version, end_state, address_list = get_ip_interface(interface, version,
module) module)
@ -715,9 +500,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages MTU settings on Nexus switch. short_description: Manages MTU settings on Nexus switch.
description: description:
- Manages MTU settings on Nexus switch. - Manages MTU settings on Nexus switch.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: notes:
@ -118,245 +117,19 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
from ansible.module_utils.nxos import load_config, run_commands
import json from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import AnsibleModule
# 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -503,10 +276,16 @@ def main():
sysmtu=dict(type='str'), sysmtu=dict(type='str'),
state=dict(choices=['absent', 'present'], default='present'), 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=[['mtu', 'interface']], required_together=[['mtu', 'interface']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
interface = module.params['interface'] interface = module.params['interface']
mtu = module.params['mtu'] mtu = module.params['mtu']
sysmtu = module.params['sysmtu'] sysmtu = module.params['sysmtu']
@ -576,7 +355,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
if interface: if interface:
end_state = get_mtu(interface, module) end_state = get_mtu(interface, module)
else: else:
@ -590,9 +369,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages core NTP configuration. short_description: Manages core NTP configuration.
description: description:
- Manages core NTP configuration. - Manages core NTP configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
options: options:
@ -125,243 +124,23 @@ changed:
sample: true 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -530,12 +309,19 @@ def main():
source_int=dict(type='str'), source_int=dict(type='str'),
state=dict(choices=['absent', 'present'], default='present'), 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=[ mutually_exclusive=[
['server','peer'], ['server','peer'],
['source_addr','source_int']], ['source_addr','source_int']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
server = module.params['server'] or None server = module.params['server'] or None
peer = module.params['peer'] or None peer = module.params['peer'] or None
key_id = module.params['key_id'] key_id = module.params['key_id']
@ -616,7 +402,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_ntp_existing(address, peer_type, module)[0] end_state = get_ntp_existing(address, peer_type, module)[0]
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -626,6 +412,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
results['peer_server_list'] = peer_server_list results['peer_server_list'] = peer_server_list
@ -635,3 +422,4 @@ def main():
from ansible.module_utils.basic import * from ansible.module_utils.basic import *
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages NTP authentication. short_description: Manages NTP authentication.
description: description:
- Manages NTP authentication. - Manages NTP authentication.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -503,9 +282,16 @@ def main():
authentication=dict(choices=['on', 'off']), authentication=dict(choices=['on', 'off']),
state=dict(choices=['absent', 'present'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
key_id = module.params['key_id'] key_id = module.params['key_id']
md5string = module.params['md5string'] md5string = module.params['md5string']
auth_type = module.params['auth_type'] auth_type = module.params['auth_type']
@ -548,7 +334,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
try: try:
execute_config_command(cmds, module) load_config(module, cmds)
except ShellError: except ShellError:
clie = get_exception() clie = get_exception()
module.fail_json(msg=str(clie) + ": " + cmds) module.fail_json(msg=str(clie) + ": " + cmds)
@ -564,9 +350,11 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages NTP options. short_description: Manages NTP options.
description: description:
- Manages NTP options, e.g. authoritative server and logging. - Manages NTP options, e.g. authoritative server and logging.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -442,10 +222,17 @@ def main():
logging=dict(required=False, type='bool'), logging=dict(required=False, type='bool'),
state=dict(choices=['absent', 'present'], default='present'), 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']], required_one_of=[['master', 'logging']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
master = module.params['master'] master = module.params['master']
stratum = module.params['stratum'] stratum = module.params['stratum']
logging = module.params['logging'] logging = module.params['logging']
@ -500,7 +287,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_ntp_options(module) end_state = get_ntp_options(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -510,6 +297,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -517,3 +305,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -16,10 +16,11 @@
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
# #
ANSIBLE_METADATA = {
ANSIBLE_METADATA = {'status': ['preview'], 'status': ['preview'],
'supported_by': 'core', 'supported_by': 'core',
'version': '1.0'} 'version': '1.0'
}
DOCUMENTATION = """ DOCUMENTATION = """
--- ---
@ -32,7 +33,6 @@ description:
NXAPI feature is absent from the configuration by default. Since NXAPI feature is absent from the configuration by default. Since
this module manages the NXAPI feature it only supports the use this module manages the NXAPI feature it only supports the use
of the C(Cli) transport. of the C(Cli) transport.
extends_documentation_fragment: nxos
options: options:
http_port: http_port:
description: description:
@ -84,15 +84,6 @@ options:
default: no default: no
choices: ['yes', 'no'] choices: ['yes', 'no']
aliases: ['enable_sandbox'] 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: state:
description: description:
- The C(state) argument controls whether or not the NXAPI - The C(state) argument controls whether or not the NXAPI
@ -106,17 +97,9 @@ options:
""" """
EXAMPLES = """ 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 - name: Enable NXAPI access with default configuration
nxos_nxapi: nxos_nxapi:
provider: "{{ cli }}" state: present
- name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled - name: Enable NXAPI with no HTTP, HTTPS at port 9443 and sandbox disabled
nxos_nxapi: nxos_nxapi:
@ -124,12 +107,10 @@ vars:
https_port: 9443 https_port: 9443
https: yes https: yes
enable_sandbox: no enable_sandbox: no
provider: "{{ cli }}"
- name: remove NXAPI configuration - name: remove NXAPI configuration
nxos_nxapi: nxos_nxapi:
state: absent state: absent
provider: "{{ cli }}"
""" """
RETURN = """ RETURN = """
@ -142,189 +123,172 @@ updates:
sample: ['no feature nxapi'] sample: ['no feature nxapi']
""" """
import re import re
import time
from ansible.module_utils.netcfg import NetworkConfig, dumps from functools import partial
from ansible.module_utils.nxos import NetworkModule, NetworkError
from ansible.module_utils.basic import get_exception
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): def check_args(module, warnings):
func = globals().get(name) nxos_check_args(module, warnings)
if func:
return func(*args, **kwargs)
def get_instance(module): state = module.params['state']
instance = dict(state='absent')
try:
resp = module.cli('show nxapi', 'json')
except NetworkError:
return instance
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] if module.params['transport'] == 'nxapi':
instance['http_port'] = resp[0].get('http_port') or 80 module.fail_json(msg='module not supported over nxapi transport')
instance['https'] = 'https_port' in resp[0] for key in ['config']:
instance['https_port'] = resp[0].get('https_port') or 443 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): needs_update = lambda x: want.get(x) is not None and (want.get(x) != have.get(x))
if needs_update('state'):
if want['state'] == 'absent':
return ['no feature nxapi']
commands.append('feature nxapi') 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)
def absent(module, instance, commands): if any((needs_update('http'), needs_update('http_port'))):
if instance['state'] != 'absent': if want['http'] is True or (want['http'] is None and have['http'] is True):
commands.append('no feature nxapi') port = want['http_port'] or 80
def set_http(module, instance, commands):
port = module.params['http_port']
if not 0 <= 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) commands.append('nxapi http port %s' % port)
elif module.params['http'] is False: elif want['http'] is False:
commands.append('no nxapi http') commands.append('no nxapi http')
def set_https(module, instance, commands): if any((needs_update('https'), needs_update('https_port'))):
port = module.params['https_port'] if want['https'] is True or (want['https'] is None and have['https'] is True):
if not 0 <= port <= 65535: port = want['https_port'] or 443
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) commands.append('nxapi https port %s' % port)
elif module.params['https'] is False: elif want['https'] is False:
commands.append('no nxapi https') commands.append('no nxapi https')
def set_sandbox(module, instance, commands): if needs_update('sandbox'):
if module.params['sandbox'] is True: cmd = 'nxapi sandbox'
commands.append('nxapi sandbox') if not want['sandbox']:
elif module.params['sandbox'] is False: cmd = 'no %s' % cmd
commands.append('no nxapi sandbox') commands.append(cmd)
def get_config(module): return commands
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): def parse_http(data):
try: match = re.search('HTTP Port:\s+(\d+)', data, re.M)
checkpoint = result['__checkpoint__'] if match:
module.cli(['rollback running-config checkpoint %s' % checkpoint, return {'http': True, 'http_port': match.group(1)}
'no checkpoint %s' % checkpoint], output='text') else:
except KeyError: return {'http': False, 'http_port': None}
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): def parse_https(data):
# create a config checkpoint match = re.search('HTTPS Port:\s+(\d+)', data, re.M)
checkpoint = 'ansible_%s' % int(time.time()) if match:
module.cli(['checkpoint %s' % checkpoint], output='text') return {'https': True, 'https_port': match.group(1)}
result['__checkpoint__'] = checkpoint else:
return {'https': False, 'https_port': None}
# load the config into the device def parse_sandbox(data):
module.config.load_config(commands) match = re.search('Sandbox:\s+(.+)$', data, re.M)
return {'sandbox': match.group(1) == 'Enabled'}
# load was successfully, remove the config checkpoint def map_config_to_obj(module):
module.cli(['no checkpoint %s' % checkpoint]) out = run_commands(module, ['show nxapi'], check_rc=False)
if not out[0]:
return {'state': 'absent'}
def load(module, commands, result): out = str(out[0]).strip()
candidate = NetworkConfig(indent=2, contents='\n'.join(commands))
config = get_config(module)
configobjs = candidate.difference(config)
if configobjs: obj = {'state': 'present'}
commands = dumps(configobjs, 'commands').split('\n') obj.update(parse_http(out))
result['updates'] = commands obj.update(parse_https(out))
if not module.check_mode: obj.update(parse_sandbox(out))
load_config(module, commands, result)
result['changed'] = True
def clean_result(result): return obj
# strip out any keys that have two leading and two trailing
# underscore characters
for key in result.keys():
if PRIVATE_KEYS_RE.match(key):
del result[key]
def 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')
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')
def map_params_to_obj(module):
obj = {
'http': module.params['http'],
'http_port': module.params['http_port'],
'https': module.params['https'],
'https_port': module.params['https_port'],
'sandbox': module.params['sandbox'],
'state': module.params['state']
}
for key, value in iteritems(obj):
if value:
validator = globals().get('validate_%s' % key)
if validator:
validator(value, module)
return obj
def main(): def main():
""" main entry point for module execution """ main entry point for module execution
""" """
argument_spec = dict( argument_spec = dict(
http=dict(aliases=['enable_http'], default=True, type='bool', setter='set_http'), http=dict(aliases=['enable_http'], type='bool'),
http_port=dict(default=80, type='int', setter='set_http'), http_port=dict(type='int'),
https=dict(aliases=['enable_https'], default=False, type='bool', setter='set_https'), https=dict(aliases=['enable_https'], type='bool'),
https_port=dict(default=443, type='int', setter='set_https'), https_port=dict(type='int'),
sandbox=dict(aliases=['enable_sandbox'], default=False, type='bool'), sandbox=dict(aliases=['enable_sandbox'], type='bool'),
# Only allow configuration of NXAPI using cli transport
transport=dict(required=True, choices=['cli']),
# deprecated (Ansible 2.3) arguments
config=dict(), 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']) state=dict(default='present', choices=['started', 'stopped', 'present', 'absent'])
) )
module = NetworkModule(argument_spec=argument_spec, argument_spec.update(nxos_argument_spec)
connect_on_load=False,
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)
state = module.params['state']
result = {'changed': False}
warnings = list() 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': commands = map_obj_to_commands((want, have), module)
state = 'present' result['commands'] = commands
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 = list() if commands:
instance = get_instance(module) 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) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages configuration of an ospf instance.
description: description:
- Manages configuration of an ospf instance. - Manages configuration of an ospf instance.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
options: options:
ospf: ospf:
description: description:
@ -81,156 +80,13 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re 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 import re
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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'ospf': 'router ospf' 'ospf': 'router ospf'
@ -304,9 +160,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
ospf = str(module.params['ospf']) ospf = str(module.params['ospf'])
@ -345,3 +208,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages a VRF for an OSPF router.
description: description:
- Manages a VRF for an OSPF router. - Manages a VRF for an OSPF router.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- Value I(default) restores params default value, if any. - Value I(default) restores params default value, if any.
Otherwise it removes the existing param configuration. Otherwise it removes the existing param configuration.
@ -172,156 +171,13 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re 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 import re
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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
@ -527,9 +383,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
args = [ args = [
'vrf', 'vrf',
@ -591,3 +454,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Configures anycast gateway MAC of the switch.
description: description:
- Configures anycast gateway MAC of the switch. - Configures anycast gateway MAC of the switch.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- Default restores params default value - Default restores params default value
- Supported MAC address format are "E.E.E", "EE-EE-EE-EE-EE-EE", - Supported MAC address format are "E.E.E", "EE-EE-EE-EE-EE-EE",
@ -109,159 +108,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'anycast_gateway_mac': 'fabric forwarding anycast-gateway-mac', 'anycast_gateway_mac': 'fabric forwarding anycast-gateway-mac',
@ -372,13 +223,16 @@ def main():
argument_spec = dict( argument_spec = dict(
anycast_gateway_mac=dict(required=True, type='str'), anycast_gateway_mac=dict(required=True, type='str'),
m_facts=dict(required=False, default=False, type='bool'), 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,
argument_spec.update(nxos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
args = [ args = [
'anycast_gateway_mac' 'anycast_gateway_mac'
] ]
@ -392,22 +246,20 @@ def main():
candidate = CustomNetworkConfig(indent=3) candidate = CustomNetworkConfig(indent=3)
invoke('get_commands', module, existing, proposed, candidate) invoke('get_commands', module, existing, proposed, candidate)
try: if not module.check_mode:
response = load_config(module, candidate) load_config(module, candidate)
result.update(response)
except ShellError:
exc = get_exception()
module.fail_json(msg=str(exc))
result['connected'] = module.connected
if module._verbosity > 0: if module._verbosity > 0:
end_state = invoke('get_existing', module, args) end_state = invoke('get_existing', module, args)
result['end_state'] = end_state result['end_state'] = end_state
result['existing'] = existing result['existing'] = existing
result['proposed'] = proposed result['proposed'] = proposed
result['warnings'] = True
module.exit_json(**result) module.exit_json(**result)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages configuration of a PIM instance.
description: description:
- Manages configuration of a Protocol Independent Multicast (PIM) instance. - Manages configuration of a Protocol Independent Multicast (PIM) instance.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
options: options:
ssm_range: ssm_range:
description: description:
@ -73,159 +72,13 @@ changed:
''' '''
# COMMON CODE FOR MIGRATION
import re 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 import re
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
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
@ -291,9 +144,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
splitted_ssm_range = module.params['ssm_range'].split('.') splitted_ssm_range = module.params['ssm_range'].split('.')
if len(splitted_ssm_range) != 4 and module.params['ssm_range'] != 'none': if len(splitted_ssm_range) != 4 and module.params['ssm_range'] != 'none':
module.fail_json(msg="Valid ssm_range values are multicast addresses " module.fail_json(msg="Valid ssm_range values are multicast addresses "
@ -334,3 +194,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages PIM interface configuration. short_description: Manages PIM interface configuration.
description: description:
- Manages PIM interface configuration settings. - Manages PIM interface configuration settings.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 import time
# COMMON CODE FOR MIGRATION
import re import re
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
def execute_show_command(command, module, command_type='cli_show', text=False): 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: if 'show run' not in command and text is False:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module, text=text)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -814,9 +595,16 @@ def main():
state=dict(choices=['present', 'absent', 'default'], state=dict(choices=['present', 'absent', 'default'],
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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
sparse = module.params['sparse'] sparse = module.params['sparse']
@ -912,7 +700,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
time.sleep(1) time.sleep(1)
get_existing = get_pim_interface(module, interface) get_existing = get_pim_interface(module, interface)
end_state, jp_bidir, isauth = local_existing(get_existing) end_state, jp_bidir, isauth = local_existing(get_existing)
@ -923,6 +711,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -930,3 +719,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Manages configuration of an Protocol Independent Multicast (PIM) static - Manages configuration of an Protocol Independent Multicast (PIM) static
rendezvous point (RP) address instance. rendezvous point (RP) address instance.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- C(state=absent) remove the whole rp-address configuration, if existing. - C(state=absent) remove the whole rp-address configuration, if existing.
options: options:
@ -103,159 +102,13 @@ changed:
# COMMON CODE FOR MIGRATION
import re 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 import re
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
BOOL_PARAMS = ['bidir'] BOOL_PARAMS = ['bidir']
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
@ -357,12 +210,19 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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'], mutually_exclusive=[['group_list', 'route_map'],
['group_list', 'prefix_list'], ['group_list', 'prefix_list'],
['route_map', 'prefix_list']], ['route_map', 'prefix_list']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
args = [ args = [
@ -414,3 +274,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.1"
short_description: Tests reachability using ping from Nexus switch. short_description: Tests reachability using ping from Nexus switch.
description: description:
- Tests reachability using ping from switch to a remote destination. - Tests reachability using ping from switch to a remote destination.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -115,163 +114,9 @@ packet_loss:
type: string type: string
sample: "0.00%" sample: "0.00%"
''' '''
from ansible.module_utils.nxos import get_config, load_config, run_commands
import json from ansible.module_utils.nxos import nxos_argument_spec, check_args
import collections from ansible.module_utils.basic import AnsibleModule
# 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_summary(results_list, reference_point): def get_summary(results_list, reference_point):
summary_string = results_list[reference_point+1] summary_string = results_list[reference_point+1]
@ -313,48 +158,9 @@ def get_statistics_summary_line(response_as_list):
return index 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): 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: if not ping:
module.fail_json(msg="An unexpected error occurred. Check all params.", module.fail_json(msg="An unexpected error occurred. Check all params.",
@ -388,9 +194,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
destination = module.params['dest'] destination = module.params['dest']
count = module.params['count'] count = module.params['count']
vrf = module.params['vrf'] vrf = module.params['vrf']
@ -444,3 +257,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages port-channel interfaces. short_description: Manages port-channel interfaces.
description: description:
- Manages port-channel specific configuration parameters. - Manages port-channel specific configuration parameters.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -125,162 +124,15 @@ changed:
sample: true 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 collections
import json
# COMMON CODE FOR MIGRATION
import re import re
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
WARNINGS = [] WARNINGS = []
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
'min_links': 'lacp min-links' 'min_links': 'lacp min-links'
@ -326,75 +178,15 @@ def get_custom_value(arg, config, module):
return value 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show port-channel summary' in command: if 'show port-channel summary' in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -654,9 +446,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
group = str(module.params['group']) group = str(module.params['group'])
mode = module.params['mode'] mode = module.params['mode']
min_links = module.params['min_links'] min_links = module.params['min_links']
@ -723,7 +522,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
output = execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state, interface_exist = get_existing(module, args) end_state, interface_exist = get_existing(module, args)
if 'configure' in cmds: if 'configure' in cmds:
@ -735,6 +534,7 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
if WARNINGS: if WARNINGS:
results['warnings'] = WARNINGS results['warnings'] = WARNINGS
@ -744,3 +544,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: 2.2
short_description: Reboot a network device. short_description: Reboot a network device.
description: description:
- Reboot a network device. - Reboot a network device.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -58,244 +57,40 @@ rebooted:
sample: true sample: true
''' '''
import json from ansible.module_utils.nxos import get_config, load_config, run_commands
import collections from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import AnsibleModule
# 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 reboot(module): def reboot(module):
disable_confirmation(module) cmds = [
execute_show_command(['reload'], module, command_type='cli_show_ascii') {'command': 'terminal-dont-ask'},
{'command': 'reload', 'output': 'text'}
]
def execute_show(cmds, module, command_type=None): run_commands(module, cmds)
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]
def main(): def main():
argument_spec = dict( argument_spec = {}
confirm=dict(required=True, type='bool'), argument_spec.update(nxos_argument_spec)
include_defaults=dict(default=False),
config=dict(), module = AnsibleModule(argument_spec=argument_spec,
save=dict(type='bool', default=False)
)
module = get_network_module(argument_spec=argument_spec,
supports_check_mode=True) supports_check_mode=True)
confirm = module.params['confirm'] warnings = list()
if not confirm: check_args(module, warnings)
module.fail_json(msg='confirm must be set to true for this '
'module to work.')
changed = False
rebooted = False
if not module.check_mode:
reboot(module) reboot(module)
changed = True changed = True
rebooted = True
results = {} results = {
results['changed'] = changed 'changed': True,
results['rebooted'] = rebooted 'warnings': warnings
}
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- This module offers the ability to set a configuration checkpoint - This module offers the ability to set a configuration checkpoint
file or rollback to a configuration checkpoint file on Cisco NXOS file or rollback to a configuration checkpoint file on Cisco NXOS
switches. switches.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -77,159 +76,13 @@ status:
''' '''
# COMMON CODE FOR MIGRATION
import re 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 import re
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_commands(cmds, module, command_type=None): def execute_commands(cmds, module, command_type=None):
@ -297,7 +150,10 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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', mutually_exclusive=[['checkpoint_file',
'rollback_to']], 'rollback_to']],
supports_check_mode=False) supports_check_mode=False)
@ -326,3 +182,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Perform SMUs on Cisco NX-OS devices. short_description: Perform SMUs on Cisco NX-OS devices.
description: description:
- Perform software maintenance upgrades (SMUs) on Cisco NX-OS devices. - Perform software maintenance upgrades (SMUs) on Cisco NX-OS devices.
extends_documentation_fragment: nxos
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
notes: notes:
- The module can only activate and commit a package, - The module can only activate and commit a package,
@ -80,202 +79,24 @@ changed:
sample: true 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 time
import json
import collections import collections
# COMMON CODE FOR MIGRATION
import re import re
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
cmds = [command] cmds = [command]
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -288,28 +109,9 @@ def remote_file_exists(module, dst, file_system='bootflash:'):
return True 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): def apply_patch(module, commands):
for command in commands: for command in commands:
response = execute_config_command([command], module) load_config(module, [command])
time.sleep(5) time.sleep(5)
if 'failed' in response: if 'failed' in response:
module.fail_json(msg="Operation failed!", response=response) module.fail_json(msg="Operation failed!", response=response)
@ -350,9 +152,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
pkg = module.params['pkg'] pkg = module.params['pkg']
file_system = module.params['file_system'] file_system = module.params['file_system']
changed = False changed = False
@ -382,3 +191,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Create snapshots of the running states of selected features, add - Create snapshots of the running states of selected features, add
new show commands for snapshot creation, delete and compare new show commands for snapshot creation, delete and compare
existing snapshots. existing snapshots.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -209,199 +208,22 @@ changed:
sample: true 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 import os
# COMMON CODE FOR MIGRATION
import re import re
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
def execute_show_command(command, module, command_type='cli_show_ascii'): def execute_show_command(command, module, command_type='cli_show_ascii'):
cmds = [command] cmds = [command]
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
body = execute_show(cmds, module) body = run_commands(module, cmds)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -535,24 +357,6 @@ def invoke(name, *args, **kwargs):
return func(*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): def get_snapshot(module):
command = 'show snapshot dump {0}'.format(module.params['snapshot_name']) command = 'show snapshot dump {0}'.format(module.params['snapshot_name'])
body = execute_show_command(command, module)[0] body = execute_show_command(command, module)[0]
@ -594,11 +398,18 @@ def main():
default=False), default=False),
path=dict(required=False, type='str', default='./') 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', mutually_exclusive=[['delete_all',
'delete_snapshot']], 'delete_snapshot']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
action = module.params['action'] action = module.params['action']
comparison_results_file = module.params['comparison_results_file'] comparison_results_file = module.params['comparison_results_file']
@ -647,7 +458,7 @@ def main():
result['updates'] = [] result['updates'] = []
else: else:
if action_results: if action_results:
execute_config_command(action_results, module) load_config(module, action_results)
changed = True changed = True
final_snapshots = invoke('get_existing', module) final_snapshots = invoke('get_existing', module)
result['updates'] = action_results result['updates'] = action_results
@ -672,3 +483,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages SNMP community configs. short_description: Manages SNMP community configs.
description: description:
- Manages SNMP community configuration. - Manages SNMP community configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -98,231 +97,14 @@ changed:
sample: true 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -435,11 +216,18 @@ def main():
acl=dict(type='str'), acl=dict(type='str'),
state=dict(choices=['absent', 'present'], default='present'), 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']], required_one_of=[['access', 'group']],
mutually_exclusive=[['access', 'group']], mutually_exclusive=[['access', 'group']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
access = module.params['access'] access = module.params['access']
group = module.params['group'] group = module.params['group']
community = module.params['community'] community = module.params['community']
@ -484,7 +272,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_community(module, community) end_state = get_snmp_community(module, community)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -495,9 +283,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages SNMP contact info. short_description: Manages SNMP contact info.
description: description:
- Manages SNMP contact information. - Manages SNMP contact information.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -83,231 +82,14 @@ changed:
sample: true 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -357,9 +138,16 @@ def main():
state=dict(choices=['absent', 'present'], state=dict(choices=['absent', 'present'],
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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
contact = module.params['contact'] contact = module.params['contact']
state = module.params['state'] state = module.params['state']
@ -382,7 +170,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_contact(module) end_state = get_snmp_contact(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -393,9 +181,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages SNMP host configuration. short_description: Manages SNMP host configuration.
description: description:
- Manages SNMP host configuration parameters. - Manages SNMP host configuration parameters.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -540,9 +321,16 @@ def main():
snmp_type=dict(choices=['trap', 'inform'], default='trap'), snmp_type=dict(choices=['trap', 'inform'], default='trap'),
state=dict(choices=['absent', 'present'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
snmp_host = module.params['snmp_host'] snmp_host = module.params['snmp_host']
community = module.params['community'] community = module.params['community']
@ -620,7 +408,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_host(snmp_host, module) end_state = get_snmp_host(snmp_host, module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -634,9 +422,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages SNMP location information. short_description: Manages SNMP location information.
description: description:
- Manages SNMP location configuration. - Manages SNMP location configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -90,231 +89,14 @@ changed:
sample: true 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -376,9 +157,16 @@ def main():
state=dict(choices=['absent', 'present'], state=dict(choices=['absent', 'present'],
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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
location = module.params['location'] location = module.params['location']
state = module.params['state'] state = module.params['state']
@ -402,7 +190,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_location(module) end_state = get_snmp_location(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -413,6 +201,7 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
@ -420,3 +209,4 @@ def main():
from ansible.module_utils.basic import * from ansible.module_utils.basic import *
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages SNMP traps. short_description: Manages SNMP traps.
description: description:
- Manages SNMP traps configurations. - Manages SNMP traps configurations.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -461,9 +242,16 @@ def main():
'sysmgr', 'system', 'upgrade', 'vtp', 'all'], 'sysmgr', 'system', 'upgrade', 'vtp', 'all'],
required=True), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
group = module.params['group'].lower() group = module.params['group'].lower()
state = module.params['state'] state = module.params['state']
@ -480,7 +268,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_traps(group, module) end_state = get_snmp_traps(group, module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -491,9 +279,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages SNMP users for monitoring. short_description: Manages SNMP users for monitoring.
description: description:
- Manages SNMP user configuration. - Manages SNMP user configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: notes:
@ -112,231 +111,14 @@ changed:
type: boolean type: boolean
sample: true 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 import re
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
def execute_show_command(command, module, command_type='cli_show', text=False): 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: if 'show run' not in command and text is False:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module, text=text)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -462,11 +243,18 @@ def main():
encrypt=dict(type='bool'), encrypt=dict(type='bool'),
state=dict(choices=['absent', 'present'], default='present'), 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'], required_together=[['authentication', 'pwd'],
['encrypt', 'privacy']], ['encrypt', 'privacy']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
user = module.params['user'] user = module.params['user']
group = module.params['group'] group = module.params['group']
pwd = module.params['pwd'] pwd = module.params['pwd']
@ -540,7 +328,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_snmp_user(user, module) end_state = get_snmp_user(user, module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -552,6 +340,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -559,3 +348,4 @@ def main():
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View file

@ -27,7 +27,6 @@ short_description: Manages static route configuration
description: description:
- Manages static route configuration - Manages static route configuration
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- If no vrf is supplied, vrf is set to default. - If no vrf is supplied, vrf is set to default.
- If C(state=absent), the route will be removed, regardless of the - If C(state=absent), the route will be removed, regardless of the
@ -111,159 +110,12 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
import ansible.module_utils.nxos from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine, dumps from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.network import NetworkModule 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)
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
def invoke(name, *args, **kwargs): def invoke(name, *args, **kwargs):
func = globals().get(name) func = globals().get(name)
@ -429,9 +281,14 @@ def main():
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
result = dict(changed=False) result = dict(changed=False)
@ -448,12 +305,7 @@ def main():
candidate = CustomNetworkConfig(indent=3) candidate = CustomNetworkConfig(indent=3)
invoke('state_%s' % state, module, candidate, prefix) invoke('state_%s' % state, module, candidate, prefix)
try: load_config(module, candidate)
response = load_config(module, candidate)
result.update(response)
except Exception:
exc = get_exception()
module.fail_json(msg=str(exc))
else: else:
result['updates'] = [] result['updates'] = []
@ -470,3 +322,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -25,7 +25,6 @@ DOCUMENTATION = '''
module: nxos_switchport module: nxos_switchport
version_added: "2.1" version_added: "2.1"
short_description: Manages Layer 2 switchport interfaces. short_description: Manages Layer 2 switchport interfaces.
extends_documentation_fragment: nxos
description: description:
- Manages Layer 2 interfaces - Manages Layer 2 interfaces
author: Jason Edelman (@jedelman8) author: Jason Edelman (@jedelman8)
@ -154,161 +153,14 @@ changed:
sample: true 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 import re
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_interface_type(interface): def get_interface_type(interface):
"""Gets the type of interface """Gets the type of interface
@ -605,86 +457,15 @@ def apply_value_map(value_map, resource):
return 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'status' not in command: if 'status' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -711,12 +492,19 @@ def main():
state=dict(choices=['absent', 'present', 'unconfigured'], state=dict(choices=['absent', 'present', 'unconfigured'],
default='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=[['access_vlan', 'trunk_vlans'], mutually_exclusive=[['access_vlan', 'trunk_vlans'],
['access_vlan', 'native_vlan'], ['access_vlan', 'native_vlan'],
['access_vlan', 'trunk_allowed_vlans']], ['access_vlan', 'trunk_allowed_vlans']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
interface = module.params['interface'] interface = module.params['interface']
mode = module.params['mode'] mode = module.params['mode']
access_vlan = module.params['access_vlan'] access_vlan = module.params['access_vlan']
@ -817,7 +605,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_switchport(interface, module) end_state = get_switchport(interface, module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -828,8 +616,10 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages UDLD global configuration params. short_description: Manages UDLD global configuration params.
description: description:
- Manages UDLD global configuration params. - Manages UDLD global configuration params.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -435,10 +216,17 @@ def main():
reset=dict(required=False, type='bool'), reset=dict(required=False, type='bool'),
state=dict(choices=['absent', 'present'], default='present'), 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']], required_one_of=[['aggressive', 'msg_time', 'reset']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
aggressive = module.params['aggressive'] aggressive = module.params['aggressive']
msg_time = module.params['msg_time'] msg_time = module.params['msg_time']
reset = module.params['reset'] reset = module.params['reset']
@ -486,7 +274,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_udld_global(module) end_state = get_udld_global(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -497,9 +285,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages UDLD interface configuration params. short_description: Manages UDLD interface configuration params.
description: description:
- Manages UDLD interface configuration params. - Manages UDLD interface configuration params.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
notes: 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 import re
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'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -466,9 +247,16 @@ def main():
interface=dict(type='str', required=True), interface=dict(type='str', required=True),
state=dict(choices=['absent', 'present'], default='present'), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
mode = module.params['mode'] mode = module.params['mode']
state = module.params['state'] state = module.params['state']
@ -500,7 +288,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_udld_interface(module, interface) end_state = get_udld_interface(module, interface)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -511,8 +299,10 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -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 <http://www.gnu.org/licenses/>.
#
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 '<PASSWORD>'
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()

View file

@ -28,7 +28,6 @@ short_description: Manages VLAN resources and attributes.
description: description:
- Manages VLAN configurations on NX-OS switches. - Manages VLAN configurations on NX-OS switches.
author: Jason Edelman (@jedelman8) author: Jason Edelman (@jedelman8)
extends_documentation_fragment: nxos
options: options:
vlan_id: vlan_id:
description: description:
@ -153,163 +152,15 @@ changed:
sample: true 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 import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import run_commands, load_config, get_config
from ansible.module_utils.shell import ShellError from ansible.module_utils.basic import AnsibleModule
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 vlan_range_to_list(vlans): def vlan_range_to_list(vlans):
result = [] result = []
@ -396,8 +247,7 @@ def get_vlan_config_commands(vlan, vid):
def get_list_of_vlans(module): def get_list_of_vlans(module):
command = 'show vlan' body = run_commands(module, ['show vlan | json'])
body = execute_show_command(command, module)
vlan_list = [] vlan_list = []
vlan_table = body[0].get('TABLE_vlanbrief')['ROW_vlanbrief'] vlan_table = body[0].get('TABLE_vlanbrief')['ROW_vlanbrief']
@ -411,8 +261,10 @@ def get_list_of_vlans(module):
def get_vni(vlanid, module): def get_vni(vlanid, module):
command = 'show run all | section vlan.{0}'.format(vlanid) flags = str('all | section vlan.{0}'.format(vlanid)).split(' ')
body = execute_show_command(command, module, command_type='cli_show_ascii')[0] 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 = '' value = ''
if body: if body:
REGEX = re.compile(r'(?:vn-segment\s)(?P<value>.*)$', re.M) REGEX = re.compile(r'(?:vn-segment\s)(?P<value>.*)$', re.M)
@ -424,10 +276,11 @@ def get_vni(vlanid, module):
def get_vlan(vlanid, module): def get_vlan(vlanid, module):
"""Get instance of VLAN as a dictionary """Get instance of VLAN as a dictionary
""" """
command = 'show vlan id %s | json' % vlanid
body = run_commands(module, [command])
command = 'show vlan id ' + vlanid #command = 'show vlan id ' + vlanid
#body = execute_show_command(command, module)
body = execute_show_command(command, module)
try: try:
vlan_table = body[0]['TABLE_vlanbriefid']['ROW_vlanbriefid'] 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)] resource[key] = value[resource.get(key)]
return 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.
"""
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(): def main():
argument_spec = dict( argument_spec = dict(
vlan_id=dict(required=False, type='str'), vlan_id=dict(required=False, type='str'),
@ -567,11 +336,24 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) save=dict(type='bool', default=False)
) )
module = get_network_module(argument_spec=argument_spec,
argument_spec.update(nxos_argument_spec)
argument_spec.update(nxos_argument_spec)
module = AnsibleModule(argument_spec=argument_spec,
mutually_exclusive=[['vlan_range', 'name'], mutually_exclusive=[['vlan_range', 'name'],
['vlan_id', 'vlan_range']], ['vlan_id', 'vlan_range']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
warnings = list()
check_args(module, warnings)
vlan_range = module.params['vlan_range'] vlan_range = module.params['vlan_range']
vlan_id = module.params['vlan_id'] vlan_id = module.params['vlan_id']
name = module.params['name'] name = module.params['name']
@ -636,7 +418,7 @@ def main():
module.exit_json(changed=True, module.exit_json(changed=True,
commands=commands) commands=commands)
else: else:
execute_config_command(commands, module) load_config(module, commands)
changed = True changed = True
end_state_vlans_list = numerical_sort(get_list_of_vlans(module)) end_state_vlans_list = numerical_sort(get_list_of_vlans(module))
if 'configure' in commands: if 'configure' in commands:
@ -653,9 +435,12 @@ def main():
results['end_state_vlans_list'] = end_state_vlans_list results['end_state_vlans_list'] = end_state_vlans_list
results['updates'] = commands results['updates'] = commands
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages global VPC configuration short_description: Manages global VPC configuration
description: description:
- Manages global VPC configuration - Manages global VPC configuration
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -145,243 +144,20 @@ changed:
sample: true sample: true
''' '''
import json from ansible.module_utils.nxos import get_config, load_config, run_commands
import collections from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import AnsibleModule
# COMMON CODE FOR MIGRATION 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.
"""
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if "section" not in command: if "section" not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -577,9 +353,15 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
domain = module.params['domain'] domain = module.params['domain']
role_priority = module.params['role_priority'] role_priority = module.params['role_priority']
system_priority = module.params['system_priority'] system_priority = module.params['system_priority']
@ -640,7 +422,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_vpc(module) end_state = get_vpc(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -651,9 +433,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.2"
short_description: Manages interface VPC configuration short_description: Manages interface VPC configuration
description: description:
- Manages interface VPC configuration - Manages interface VPC configuration
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -97,240 +96,19 @@ changed:
''' '''
import collections from ansible.module_utils.nxos import get_config, load_config, run_commands
import json from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.basic import AnsibleModule
# COMMON CODE FOR MIGRATION 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:
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -485,10 +263,17 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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']], mutually_exclusive=[['vpc', 'peer_link']],
supports_check_mode=True) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
portchannel = module.params['portchannel'] portchannel = module.params['portchannel']
vpc = module.params['vpc'] vpc = module.params['vpc']
peer_link = module.params['peer_link'] peer_link = module.params['peer_link']
@ -570,7 +355,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
output = execute_config_command(cmds, module) load_config(module, cmds)
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
output = ' '.join(output) output = ' '.join(output)
if 'error' in output.lower(): if 'error' in output.lower():
@ -585,9 +370,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.1"
short_description: Manages global VRF configuration. short_description: Manages global VRF configuration.
description: description:
- Manages global VRF configuration. - Manages global VRF configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -117,238 +116,23 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import json
# COMMON CODE FOR MIGRATION
import re import re
import ansible.module_utils.nxos from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError from ansible.module_utils.netcfg import CustomNetworkConfig
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
def execute_show_command(command, module, command_type='cli_show'): 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: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh_vrf(module, command, response) else:
elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -457,9 +241,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
vrf = module.params['vrf'] vrf = module.params['vrf']
admin_state = module.params['admin_state'].lower() admin_state = module.params['admin_state'].lower()
description = module.params['description'] description = module.params['description']
@ -512,7 +303,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=commands) module.exit_json(changed=True, commands=commands)
else: else:
execute_config_command(commands, module) load_config(module, commands)
changed = True changed = True
end_state = get_vrf(vrf, module) end_state = get_vrf(vrf, module)
if 'configure' in commands: if 'configure' in commands:
@ -524,9 +315,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = commands results['updates'] = commands
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ short_description: Manages VRF AF.
description: description:
- Manages VRF AF - Manages VRF AF
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- Default, where supported, restores params default value. - Default, where supported, restores params default value.
options: options:
@ -104,159 +103,12 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError 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
BOOL_PARAMS = ['route_target_both_auto_evpn'] BOOL_PARAMS = ['route_target_both_auto_evpn']
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
@ -378,9 +230,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
args = [ args = [
@ -434,3 +293,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -27,7 +27,6 @@ version_added: "2.1"
short_description: Manages interface specific VRF configuration. short_description: Manages interface specific VRF configuration.
description: description:
- Manages interface specific VRF configuration. - Manages interface specific VRF configuration.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -97,240 +96,25 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import json
import collections
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError 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 = [] 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh_vrf_interface(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -428,9 +212,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
vrf = module.params['vrf'] vrf = module.params['vrf']
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
state = module.params['state'] state = module.params['state']
@ -486,7 +277,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=commands) module.exit_json(changed=True, commands=commands)
else: else:
execute_config_command(commands, module) load_config(module, commands)
changed = True changed = True
changed_vrf = get_interface_info(interface, module) changed_vrf = get_interface_info(interface, module)
end_state = dict(interface=interface, vrf=changed_vrf) end_state = dict(interface=interface, vrf=changed_vrf)
@ -508,3 +299,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.1"
short_description: Manages VRRP configuration on NX-OS switches. short_description: Manages VRRP configuration on NX-OS switches.
description: description:
- Manages VRRP configuration on NX-OS switches. - Manages VRRP configuration on NX-OS switches.
extends_documentation_fragment: nxos
author: author:
- Jason Edelman (@jedelman8) - Jason Edelman (@jedelman8)
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
@ -135,245 +134,21 @@ changed:
type: boolean type: boolean
sample: true sample: true
''' '''
import json
import collections
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.shell import ShellError 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
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
def execute_show_command(command, module, command_type='cli_show'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh_vrrp(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -587,9 +362,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
group = module.params['group'] group = module.params['group']
@ -648,7 +430,7 @@ def main():
if module.check_mode: if module.check_mode:
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
execute_config_command(cmds, module) load_config(module, cmds)
changed = True changed = True
end_state = get_existing_vrrp(interface, group, module, name) end_state = get_existing_vrrp(interface, group, module, name)
if 'configure' in cmds: if 'configure' in cmds:
@ -659,6 +441,7 @@ def main():
results['existing'] = existing results['existing'] = existing
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
results['end_state'] = end_state results['end_state'] = end_state
module.exit_json(**results) module.exit_json(**results)
@ -666,3 +449,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -26,7 +26,6 @@ version_added: "2.2"
short_description: Manages VTP domain configuration. short_description: Manages VTP domain configuration.
description: description:
- Manages VTP domain configuration. - Manages VTP domain configuration.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -84,243 +83,22 @@ 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
# COMMON CODE FOR MIGRATION from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import CustomNetworkConfig
import re 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'status' not in command: if 'status' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -380,9 +158,16 @@ def main():
argument_spec = dict( argument_spec = dict(
domain=dict(type='str', required=True), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
domain = module.params['domain'] domain = module.params['domain']
existing = get_vtp_config(module) existing = get_vtp_config(module)
@ -404,7 +189,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_vtp_config(module) end_state = get_vtp_config(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -415,9 +200,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages VTP password configuration. short_description: Manages VTP password configuration.
description: description:
- Manages VTP password configuration. - Manages VTP password configuration.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -101,243 +100,22 @@ changed:
sample: true 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
# COMMON CODE FOR MIGRATION from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.netcfg import CustomNetworkConfig
import re 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'): def execute_show_command(command, module, command_type='cli_show'):
if module.params['transport'] == 'cli': if module.params['transport'] == 'cli':
if 'show run' not in command: if 'show run' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -412,9 +190,16 @@ def main():
state=dict(choices=['absent', 'present'], state=dict(choices=['absent', 'present'],
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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
vtp_password = module.params['vtp_password'] or None vtp_password = module.params['vtp_password'] or None
state = module.params['state'] state = module.params['state']
@ -461,7 +246,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_vtp_config(module) end_state = get_vtp_config(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -472,9 +257,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -28,7 +28,6 @@ version_added: "2.2"
short_description: Manages VTP version configuration. short_description: Manages VTP version configuration.
description: description:
- Manages VTP version configuration. - Manages VTP version configuration.
extends_documentation_fragment: nxos
author: author:
- Gabriele Gerbino (@GGabriele) - Gabriele Gerbino (@GGabriele)
notes: notes:
@ -79,231 +78,14 @@ changed:
type: boolean type: boolean
sample: true 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 import re
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'): 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: if 'status' not in command:
command += ' | json' command += ' | json'
cmds = [command] cmds = [command]
response = execute_show(cmds, module) body = run_commands(module, cmds)
body = get_cli_body_ssh(command, response, module)
elif module.params['transport'] == 'nxapi': elif module.params['transport'] == 'nxapi':
cmds = [command] cmds = [command]
body = execute_show(cmds, module, command_type=command_type) body = run_commands(module, cmds)
return body return body
@ -375,9 +156,16 @@ def main():
argument_spec = dict( argument_spec = dict(
version=dict(type='str', choices=['1', '2'], required=True), 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
version = module.params['version'] version = module.params['version']
existing = get_vtp_config(module) existing = get_vtp_config(module)
@ -399,7 +187,7 @@ def main():
module.exit_json(changed=True, commands=cmds) module.exit_json(changed=True, commands=cmds)
else: else:
changed = True changed = True
execute_config_command(cmds, module) load_config(module, cmds)
end_state = get_vtp_config(module) end_state = get_vtp_config(module)
if 'configure' in cmds: if 'configure' in cmds:
cmds.pop(0) cmds.pop(0)
@ -410,9 +198,11 @@ def main():
results['end_state'] = end_state results['end_state'] = end_state
results['updates'] = cmds results['updates'] = cmds
results['changed'] = changed results['changed'] = changed
results['warnings'] = warnings
module.exit_json(**results) module.exit_json(**results)
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Manages VXLAN Network Virtualization Endpoint (NVE) overlay interface - Manages VXLAN Network Virtualization Endpoint (NVE) overlay interface
that terminates VXLAN tunnels. that terminates VXLAN tunnels.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- The module is used to manage NVE properties, not to create NVE - The module is used to manage NVE properties, not to create NVE
interfaces. Use M(nxos_interface) if you wish to do so. interfaces. Use M(nxos_interface) if you wish to do so.
@ -124,159 +123,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
BOOL_PARAMS = [ BOOL_PARAMS = [
'shutdown', 'shutdown',
@ -458,9 +309,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
state = module.params['state'] state = module.params['state']
interface = module.params['interface'].lower() interface = module.params['interface'].lower()
@ -528,3 +386,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -29,7 +29,6 @@ description:
- Creates a Virtual Network Identifier member (VNI) for an NVE - Creates a Virtual Network Identifier member (VNI) for an NVE
overlay interface. overlay interface.
author: Gabriele Gerbino (@GGabriele) author: Gabriele Gerbino (@GGabriele)
extends_documentation_fragment: nxos
notes: notes:
- default, where supported, restores params default value. - default, where supported, restores params default value.
options: options:
@ -143,159 +142,11 @@ changed:
sample: true sample: true
''' '''
# COMMON CODE FOR MIGRATION
import re import re
from ansible.module_utils.nxos import get_config, load_config, run_commands
from ansible.module_utils.basic import get_exception from ansible.module_utils.nxos import nxos_argument_spec, check_args
from ansible.module_utils.netcfg import NetworkConfig, ConfigLine from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.shell import ShellError 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
BOOL_PARAMS = ['suppress_arp'] BOOL_PARAMS = ['suppress_arp']
PARAM_TO_COMMAND_KEYMAP = { PARAM_TO_COMMAND_KEYMAP = {
@ -496,9 +347,16 @@ def main():
config=dict(), config=dict(),
save=dict(type='bool', default=False) 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) supports_check_mode=True)
warnings = list()
check_args(module, warnings)
if module.params['assoc_vrf']: if module.params['assoc_vrf']:
mutually_exclusive_params = ['multicast_group', mutually_exclusive_params = ['multicast_group',
'suppress_arp', 'suppress_arp',
@ -587,3 +445,4 @@ def main():
if __name__ == '__main__': if __name__ == '__main__':
main() main()

View file

@ -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 <http://www.gnu.org/licenses/>.
#
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

View file

@ -19,10 +19,95 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
from ansible.plugins.action import ActionBase import os
from ansible.plugins.action.net_config import ActionModule as NetActionModule import re
import time
import glob
class ActionModule(NetActionModule, ActionBase): from ansible.plugins.action.nxos import ActionModule as _ActionModule
pass 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)

View file

@ -19,9 +19,84 @@
from __future__ import (absolute_import, division, print_function) from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
from ansible.plugins.action import ActionBase import os
from ansible.plugins.action.net_template import ActionModule as NetActionModule import time
import glob
import urlparse
class ActionModule(NetActionModule, ActionBase): from ansible.module_utils._text import to_text
pass 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)

View file

@ -52,11 +52,3 @@ class TerminalModule(TerminalBase):
except AnsibleConnectionFailure: except AnsibleConnectionFailure:
raise AnsibleConnectionFailure('unable to set terminal parameters') 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'