cba66dfedc
* updates the deprecated ios_template module to use network_cli * adds unit test cases for ios_template * adds check for provider argument and displays warning message
198 lines
6.8 KiB
Python
198 lines
6.8 KiB
Python
# 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.
|
|
#
|
|
# Copyright (c) 2015 Peter Sprygada, <psprygada@ansible.com>
|
|
#
|
|
# 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.
|
|
#
|
|
from ansible.module_utils.basic import AnsibleModule
|
|
from ansible.module_utils.basic import env_fallback, get_exception
|
|
from ansible.module_utils.netcli import Cli, Command
|
|
from ansible.module_utils._text import to_native
|
|
from ansible.module_utils.six import iteritems
|
|
|
|
NET_TRANSPORT_ARGS = dict(
|
|
host=dict(required=True),
|
|
port=dict(type='int'),
|
|
|
|
username=dict(fallback=(env_fallback, ['ANSIBLE_NET_USERNAME'])),
|
|
password=dict(no_log=True, fallback=(env_fallback, ['ANSIBLE_NET_PASSWORD'])),
|
|
ssh_keyfile=dict(fallback=(env_fallback, ['ANSIBLE_NET_SSH_KEYFILE']), type='path'),
|
|
|
|
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'])),
|
|
|
|
provider=dict(type='dict'),
|
|
transport=dict(choices=list()),
|
|
|
|
timeout=dict(default=10, type='int')
|
|
)
|
|
|
|
NET_CONNECTION_ARGS = dict()
|
|
|
|
NET_CONNECTIONS = dict()
|
|
|
|
def _transitional_argument_spec():
|
|
argument_spec = {}
|
|
for key, value in iteritems(NET_TRANSPORT_ARGS):
|
|
value['required'] = False
|
|
argument_spec[key] = value
|
|
return argument_spec
|
|
|
|
def to_list(val):
|
|
if isinstance(val, (list, tuple)):
|
|
return list(val)
|
|
elif val is not None:
|
|
return [val]
|
|
else:
|
|
return list()
|
|
|
|
|
|
class ModuleStub(object):
|
|
def __init__(self, argument_spec, fail_json):
|
|
self.params = dict()
|
|
for key, value in argument_spec.items():
|
|
self.params[key] = value.get('default')
|
|
self.fail_json = fail_json
|
|
|
|
class NetworkError(Exception):
|
|
|
|
def __init__(self, msg, **kwargs):
|
|
super(NetworkError, self).__init__(msg)
|
|
self.kwargs = kwargs
|
|
|
|
class Config(object):
|
|
|
|
def __init__(self, connection):
|
|
self.connection = connection
|
|
|
|
def __call__(self, commands, **kwargs):
|
|
lines = to_list(commands)
|
|
return self.connection.configure(lines, **kwargs)
|
|
|
|
def load_config(self, commands, **kwargs):
|
|
commands = to_list(commands)
|
|
return self.connection.load_config(commands, **kwargs)
|
|
|
|
def get_config(self, **kwargs):
|
|
return self.connection.get_config(**kwargs)
|
|
|
|
def save_config(self):
|
|
return self.connection.save_config()
|
|
|
|
|
|
class NetworkModule(AnsibleModule):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
connect_on_load = kwargs.pop('connect_on_load', True)
|
|
|
|
argument_spec = NET_TRANSPORT_ARGS.copy()
|
|
argument_spec['transport']['choices'] = NET_CONNECTIONS.keys()
|
|
argument_spec.update(NET_CONNECTION_ARGS.copy())
|
|
|
|
if kwargs.get('argument_spec'):
|
|
argument_spec.update(kwargs['argument_spec'])
|
|
kwargs['argument_spec'] = argument_spec
|
|
|
|
super(NetworkModule, self).__init__(*args, **kwargs)
|
|
|
|
self.connection = None
|
|
self._cli = None
|
|
self._config = None
|
|
|
|
try:
|
|
transport = self.params['transport'] or '__default__'
|
|
cls = NET_CONNECTIONS[transport]
|
|
self.connection = cls()
|
|
except KeyError:
|
|
self.fail_json(msg='Unknown transport or no default transport specified')
|
|
except (TypeError, NetworkError):
|
|
exc = get_exception()
|
|
self.fail_json(msg=to_native(exc))
|
|
|
|
if connect_on_load:
|
|
self.connect()
|
|
|
|
@property
|
|
def cli(self):
|
|
if not self.connected:
|
|
self.connect()
|
|
if self._cli:
|
|
return self._cli
|
|
self._cli = Cli(self.connection)
|
|
return self._cli
|
|
|
|
@property
|
|
def config(self):
|
|
if not self.connected:
|
|
self.connect()
|
|
if self._config:
|
|
return self._config
|
|
self._config = Config(self.connection)
|
|
return self._config
|
|
|
|
@property
|
|
def connected(self):
|
|
return self.connection._connected
|
|
|
|
def _load_params(self):
|
|
super(NetworkModule, self)._load_params()
|
|
provider = self.params.get('provider') or dict()
|
|
for key, value in provider.items():
|
|
for args in [NET_TRANSPORT_ARGS, NET_CONNECTION_ARGS]:
|
|
if key in args:
|
|
if self.params.get(key) is None and value is not None:
|
|
self.params[key] = value
|
|
|
|
def connect(self):
|
|
try:
|
|
if not self.connected:
|
|
self.connection.connect(self.params)
|
|
if self.params['authorize']:
|
|
self.connection.authorize(self.params)
|
|
self.log('connected to %s:%s using %s' % (self.params['host'],
|
|
self.params['port'], self.params['transport']))
|
|
except NetworkError:
|
|
exc = get_exception()
|
|
self.fail_json(msg=to_native(exc))
|
|
|
|
def disconnect(self):
|
|
try:
|
|
if self.connected:
|
|
self.connection.disconnect()
|
|
self.log('disconnected from %s' % self.params['host'])
|
|
except NetworkError:
|
|
exc = get_exception()
|
|
self.fail_json(msg=to_native(exc))
|
|
|
|
def register_transport(transport, default=False):
|
|
def register(cls):
|
|
NET_CONNECTIONS[transport] = cls
|
|
if default:
|
|
NET_CONNECTIONS['__default__'] = cls
|
|
return cls
|
|
return register
|
|
|
|
def add_argument(key, value):
|
|
NET_CONNECTION_ARGS[key] = value
|
|
|