Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updates nxos shared module refactor #17172

Merged
merged 1 commit into from
Aug 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
188 changes: 89 additions & 99 deletions lib/ansible/module_utils/nxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,54 +18,19 @@
#

import re
import collections

from ansible.module_utils.basic import json, json_dict_bytes_to_unicode
from ansible.module_utils.network import NetCli, NetworkError, ModuleStub
from ansible.module_utils.basic import json, get_exception
from ansible.module_utils.network import NetworkModule, NetworkError, ModuleStub
from ansible.module_utils.network import add_argument, register_transport, to_list
from ansible.module_utils.shell import CliBase
from ansible.module_utils.netcfg import NetworkConfig
from ansible.module_utils.netcli import Command
from ansible.module_utils.urls import fetch_url, url_argument_spec

# temporary fix until modules are update. to be removed before 2.2 final
from ansible.module_utils.network import get_module

add_argument('use_ssl', dict(default=False, type='bool'))
add_argument('validate_certs', dict(default=True, type='bool'))

def argument_spec():
return dict(
# config options
running_config=dict(aliases=['config']),
save_config=dict(type='bool', default=False, aliases=['save']),
)
nxos_argument_spec = argument_spec()

def get_config(module):
config = module.params['running_config']
if not config:
config = module.config.get_config(include_defaults=True)
return NetworkConfig(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_config']

result = dict(changed=False)

if commands:
if not module.check_mode:
module.config(commands)
if save_config:
module.config.save_config()

result['changed'] = True
result['updates'] = commands

return result


class Nxapi(object):

Expand All @@ -85,7 +50,9 @@ def __init__(self):

def _error(self, msg, **kwargs):
self._nxapi_auth = None
raise NetworkError(msg, url=self.url)
if 'url' not in kwargs:
kwargs['url'] = self.url
raise NetworkError(msg, **kwargs)

def _get_body(self, commands, output, version='1.0', chunk='0', sid=None):
"""Encodes a NXAPI JSON request message
Expand All @@ -106,7 +73,7 @@ def _get_body(self, commands, output, version='1.0', chunk='0', sid=None):
'chunk': chunk,
'sid': sid,
'input': commands,
'output_format': output
'output_format': 'json'
}

return dict(ins_api=msg)
Expand Down Expand Up @@ -136,43 +103,79 @@ def disconnect(self, **kwargs):
self._connected = False

def execute(self, commands, output=None, **kwargs):
"""Send commands to the device.
"""
commands = to_list(commands)
commands = collections.deque(commands)
output = output or self.default_output

data = self._get_body(commands, output)
data = self._jsonify(data)
# only 10 commands can be encoded in each request
# messages sent to the remote device
stack = list()
requests = list()

while commands:
stack.append(commands.popleft())
if len(stack) == 10:
data = self._get_body(stack, output)
data = self._jsonify(data)
requests.append(data)
stack = list()

if stack:
data = self._get_body(stack, output)
data = self._jsonify(data)
requests.append(data)

headers = {'Content-Type': 'application/json'}
if self._nxapi_auth:
headers['Cookie'] = self._nxapi_auth
result = list()

response, headers = fetch_url(
self.url_args, self.url, data=data, headers=headers, method='POST'
)
self._nxapi_auth = headers.get('set-cookie')
for req in requests:
if self._nxapi_auth:
headers['Cookie'] = self._nxapi_auth

if headers['status'] != 200:
self._error(**headers)
response, headers = fetch_url(
self.url_args, self.url, data=data, headers=headers, method='POST'
)
self._nxapi_auth = headers.get('set-cookie')

try:
response = json.loads(response.read())
except ValueError:
raise NetworkError(msg='unable to load repsonse from device')
if headers['status'] != 200:
self._error(**headers)

result = list()
try:
response = json.loads(response.read())
except ValueError:
raise NetworkError(msg='unable to load response from device')

output = response['ins_api']['outputs']['output']
for item in to_list(output):
if item['code'] != '200':
self._error(**item)
else:
result.append(item['body'])
output = response['ins_api']['outputs']['output']
for item in to_list(output):
if item['code'] != '200':
self._error(output=output, **item)
else:
result.append(item['body'])

return result

### implemented by network.Config ###
### implemention of netcli.Cli ###

def run_commands(self, commands):
output = None
cmds = list()
responses = list()

for cmd in commands:
if output and output != cmd.output:
responses.extend(self.execute(cmds, output=output))
cmds = list()
output = cmd.output
cmds.append(str(cmd))

if cmds:
responses.extend(self.execute(cmds, output=output))

return responses


### end of netcli.Cli ###

### implemention of netcfg.Config ###

def configure(self, commands):
commands = to_list(commands)
Expand All @@ -184,17 +187,13 @@ def get_config(self, **kwargs):
cmd += ' all'
return self.execute([cmd], output='text')[0]

def load_config(self, **kwargs):
raise NotImplementedError

def replace_config(self, **kwargs):
raise NotImplementedError
def load_config(self, config, **kwargs):
return self.configure(config)

def commit_config(self, **kwargs):
raise NotImplementedError
def save_config(self, **kwargs):
self.execute(['copy running-config startup-config'])

def abort_config(self, **kwargs):
raise NotImplementedError
### end netcfg.Config ###

def _jsonify(self, data):
for encoding in ("utf-8", "latin-1"):
Expand All @@ -210,10 +209,12 @@ def _jsonify(self, data):
except UnicodeDecodeError:
continue
self._error(msg='Invalid unicode encoding encountered')

Nxapi = register_transport('nxapi')(Nxapi)


class Cli(NetCli):
class Cli(CliBase):

NET_PASSWD_RE = re.compile(r"[\r\n]?password: $", re.I)

CLI_PROMPTS_RE = [
Expand All @@ -238,7 +239,7 @@ def connect(self, params, **kwargs):
super(Cli, self).connect(params, kickstart=False, **kwargs)
self.shell.send('terminal length 0')

### implementation of network.Cli ###
### implementation of netcli.Cli ###

def run_commands(self, commands):
cmds = list(prepare_commands(commands))
Expand All @@ -254,34 +255,26 @@ def run_commands(self, commands):
)
return responses

### implemented by network.Config ###

def get_config(self, **kwargs):
cmd = 'show running-config'
if kwargs.get('include_defaults'):
cmd += ' all'
return self.execute([cmd])[0]
### implemented by netcfg.Config ###

def configure(self, commands, **kwargs):
commands = prepare_config(commands)
responses = self.execute(commands)
responses.pop(0)
return responses

def load_config(self):
raise NotImplementedError

def replace_config(self, **kwargs):
raise NotImplementedError

def commit_config(self):
raise NotImplementedError
def get_config(self, include_defaults=False, **kwargs):
cmd = 'show running-config'
if kwargs.get('include_defaults'):
cmd += ' all'
return self.execute([cmd])[0]

def abort_config(self):
raise NotImplementedError
def load_config(self, commands, **kwargs):
return self.configure(commands)

def save_config(self):
self.execute(['copy running-config startup-config'])

Cli = register_transport('cli', default=True)(Cli)

def prepare_config(commands):
Expand All @@ -290,12 +283,9 @@ def prepare_config(commands):
commands.append('end')
return commands


def prepare_commands(commands):
jsonify = lambda x: '%s | json' % x
for cmd in to_list(commands):
if cmd.output == 'json':
cmd = jsonify(cmd)
else:
cmd = str(cmd)
cmd.command = jsonify(cmd)
yield cmd
28 changes: 28 additions & 0 deletions lib/ansible/plugins/action/nxos_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#
# Copyright 2015 Peter Sprygada <psprygada@ansible.com>
#
# 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

from ansible.plugins.action import ActionBase
from ansible.plugins.action.net_config import ActionModule as NetActionModule

class ActionModule(NetActionModule, ActionBase):
pass