Skip to content

Commit

Permalink
Refactor EOS code to use cliconf (ansible#34426)
Browse files Browse the repository at this point in the history
* WIP Refactor EOS code to use cliconf

* Fix connection.get where sendonly is True

* Fix pylint issue

* Remove return from send_config and various exec_commands

Also, removed a few try/except, which are anyways handled in
Connection.
  • Loading branch information
rcarrillocruz authored Jan 11, 2018
1 parent 477cd3f commit 32e7c9b
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 47 deletions.
98 changes: 53 additions & 45 deletions lib/ansible/module_utils/network/eos/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

from ansible.module_utils._text import to_text, to_native
from ansible.module_utils.basic import env_fallback, return_values
from ansible.module_utils.connection import exec_command
from ansible.module_utils.connection import Connection
from ansible.module_utils.network.common.utils import to_list, ComplexList
from ansible.module_utils.six import iteritems
from ansible.module_utils.urls import fetch_url
Expand Down Expand Up @@ -112,19 +112,28 @@ def __init__(self, module):
self._module = module
self._device_configs = {}
self._session_support = None
self._connection = None

def _get_connection(self):
if self._connection:
return self._connection
self._connection = Connection(self._module._socket_path)

return self._connection

@property
def supports_sessions(self):
if self._session_support is not None:
return self._session_support
rc, out, err = self.exec_command('show configuration sessions')
self._session_support = rc == 0
return self._session_support
conn = self._get_connection()

def exec_command(self, command):
if isinstance(command, dict):
command = self._module.jsonify(command)
return exec_command(self._module, command)
self._session_support = True
try:
out = conn.get('show configuration sessions')
except:
self._session_support = False

return self._session_support

def get_config(self, flags=None):
"""Retrieves the current config from the device or cache
Expand All @@ -138,35 +147,43 @@ def get_config(self, flags=None):
try:
return self._device_configs[cmd]
except KeyError:
conn = get_connection(self)
rc, out, err = self.exec_command(cmd)
out = to_text(out, errors='surrogate_then_replace')
if rc != 0:
self._module.fail_json(msg=to_text(err, errors='surrogate_then_replace'))
cfg = str(out).strip()
conn = self._get_connection()
out = conn.get_config(flags=flags)
cfg = to_text(out, errors='surrogate_then_replace').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()
connection = self._get_connection()

for cmd in to_list(commands):
rc, out, err = self.exec_command(cmd)
out = to_text(out, errors='surrogate_then_replace')
if check_rc and rc != 0:
self._module.fail_json(msg=to_text(err, errors='surrogate_then_replace'))
if isinstance(cmd, dict):
command = cmd['command']
prompt = cmd['prompt']
answer = cmd['answer']
else:
command = cmd
prompt = None
answer = None

out = connection.get(command, prompt, answer)
out = to_text(out, errors='surrogate_or_strict')

try:
out = self._module.from_json(out)
except ValueError:
out = str(out).strip()

responses.append(out)

return responses

def send_config(self, commands):
conn = self._get_connection()

multiline = False
rc = 0
for command in to_list(commands):
Expand All @@ -175,31 +192,24 @@ def send_config(self, commands):

if command.startswith('banner') or multiline:
multiline = True
command = self._module.jsonify({'command': command, 'sendonly': True})
elif command == 'EOF' and multiline:
multiline = False

rc, out, err = self.exec_command(command)
if rc != 0:
return (rc, out, to_text(err, errors='surrogate_then_replace'))

return (rc, 'ok', '')
conn.get(command, None, None, multiline)

def configure(self, commands):
"""Sends configuration commands to the remote device
"""
conn = get_connection(self)

rc, out, err = self.exec_command('configure')
if rc != 0:
self._module.fail_json(msg='unable to enter configuration mode', output=to_text(err, errors='surrogate_then_replace'))
out = conn.get('configure')

rc, out, err = self.send_config(commands)
if rc != 0:
self.exec_command('abort')
self._module.fail_json(msg=to_text(err, errors='surrogate_then_replace'))
try:
self.send_config(commands)
except:
conn.get('abort')

self.exec_command('end')
conn.get('end')
return {}

def load_config(self, commands, commit=False, replace=False):
Expand All @@ -214,30 +224,28 @@ def load_config(self, commands, commit=False, replace=False):
if not all((bool(use_session), self.supports_sessions)):
return self.configure(self, commands)

conn = get_connection(self)
conn = self._get_connection()
session = 'ansible_%s' % int(time.time())
result = {'session': session}

rc, out, err = self.exec_command('configure session %s' % session)
if rc != 0:
self._module.fail_json(msg='unable to enter configuration mode', output=to_text(err, errors='surrogate_then_replace'))
out = conn.get('configure session %s' % session)

if replace:
self.exec_command('rollback clean-config')
out = conn.get('rollback clean-config')

rc, out, err = self.send_config(commands)
if rc != 0:
self.exec_command('abort')
self._module.fail_json(msg=to_text(err, errors='surrogate_then_replace'), commands=commands)
try:
self.send_config(commands)
except:
conn.get('abort')

rc, out, err = self.exec_command('show session-config diffs')
if rc == 0 and out:
out = conn.get('show session-config diffs')
if out:
result['diff'] = to_text(out, errors='surrogate_then_replace').strip()

if commit:
self.exec_command('commit')
conn.get('commit')
else:
self.exec_command('abort')
conn.get('abort')

return result

Expand Down
8 changes: 6 additions & 2 deletions lib/ansible/plugins/cliconf/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,18 @@ def get_device_info(self):
return device_info

@enable_mode
def get_config(self, source='running', format='text'):
def get_config(self, source='running', format='text', flags=None):
lookup = {'running': 'running-config', 'startup': 'startup-config'}
if source not in lookup:
return self.invalid_params("fetching configuration from %s is not supported" % source)
if format == 'text':
cmd = b'show %s' % lookup[source]
cmd = b'show %s ' % lookup[source]
else:
cmd = b'show %s | %s' % (lookup[source], format)

flags = [] if flags is None else flags
cmd += ' '.join(flags)
cmd = cmd.strip()
return self.send_command(cmd)

@enable_mode
Expand Down

0 comments on commit 32e7c9b

Please sign in to comment.