mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-04-25 03:41:25 -07:00
Remove cliconf from httpapi connection (#46813)
* Bare minimum rip out cliconf * nxapi changeover * Update documentation, move options * Memoize device_info * Gratuitous rename to underscore use of local api implementation Fixup eos module_utils like nxos * Streamline version and image scans * Expose get_capabilities through module_utils * Add load_config to module_utils * Support rpcs using both args and kwargs * Add get_config for nxos * Add get_diff * module context, pulled from nxapi We could probably do this correctly later * Fix eos issues * Limit connection._sub_plugin to only one plugin
This commit is contained in:
parent
32dbb99bb8
commit
02432565cd
14 changed files with 568 additions and 255 deletions
|
@ -4,8 +4,29 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
author: Ansible Networking Team
|
||||
httpapi: eos
|
||||
short_description: Use eAPI to run command on eos platform
|
||||
description:
|
||||
- This eos plugin provides low level abstraction api's for
|
||||
sending and receiving CLI commands with eos network devices.
|
||||
version_added: "2.6"
|
||||
options:
|
||||
eos_use_sessions:
|
||||
type: int
|
||||
default: 1
|
||||
description:
|
||||
- Specifies if sessions should be used on remote host or not
|
||||
env:
|
||||
- name: ANSIBLE_EOS_USE_SESSIONS
|
||||
vars:
|
||||
- name: ansible_eos_use_sessions
|
||||
version_added: '2.8'
|
||||
"""
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from ansible.module_utils._text import to_text
|
||||
from ansible.module_utils.connection import ConnectionError
|
||||
|
@ -16,7 +37,39 @@ from ansible.utils.display import Display
|
|||
display = Display()
|
||||
|
||||
|
||||
OPTIONS = {
|
||||
'format': ['text', 'json'],
|
||||
'diff_match': ['line', 'strict', 'exact', 'none'],
|
||||
'diff_replace': ['line', 'block', 'config'],
|
||||
'output': ['text', 'json']
|
||||
}
|
||||
|
||||
|
||||
class HttpApi(HttpApiBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(HttpApi, self).__init__(*args, **kwargs)
|
||||
self._device_info = None
|
||||
self._session_support = None
|
||||
|
||||
@property
|
||||
def supports_sessions(self):
|
||||
use_session = self.get_option('eos_use_sessions')
|
||||
try:
|
||||
use_session = int(use_session)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if not bool(use_session):
|
||||
self._session_support = False
|
||||
else:
|
||||
if self._session_support:
|
||||
return self._session_support
|
||||
|
||||
response = self.send_request('show configuration sessions')
|
||||
self._session_support = 'error' not in response
|
||||
|
||||
return self._session_support
|
||||
|
||||
def send_request(self, data, **message_kwargs):
|
||||
data = to_list(data)
|
||||
if self._become:
|
||||
|
@ -45,117 +98,51 @@ class HttpApi(HttpApiBase):
|
|||
|
||||
return results
|
||||
|
||||
def get_prompt(self):
|
||||
# Fake a prompt for @enable_mode
|
||||
if self._become:
|
||||
return '#'
|
||||
return '>'
|
||||
def get_device_info(self):
|
||||
if self._device_info:
|
||||
return self._device_info
|
||||
|
||||
# Imported from module_utils
|
||||
def edit_config(self, config, commit=False, replace=False):
|
||||
"""Loads the configuration onto the remote devices
|
||||
device_info = {}
|
||||
|
||||
If the device doesn't support configuration sessions, this will
|
||||
fallback to using configure() to load the commands. If that happens,
|
||||
there will be no returned diff or session values
|
||||
"""
|
||||
session = 'ansible_%s' % int(time.time())
|
||||
result = {'session': session}
|
||||
banner_cmd = None
|
||||
banner_input = []
|
||||
device_info['network_os'] = 'eos'
|
||||
reply = self.send_request('show version | json')
|
||||
data = json.loads(reply)
|
||||
|
||||
commands = ['configure session %s' % session]
|
||||
if replace:
|
||||
commands.append('rollback clean-config')
|
||||
device_info['network_os_version'] = data['version']
|
||||
device_info['network_os_model'] = data['modelName']
|
||||
|
||||
for command in config:
|
||||
if command.startswith('banner'):
|
||||
banner_cmd = command
|
||||
banner_input = []
|
||||
elif banner_cmd:
|
||||
if command == 'EOF':
|
||||
command = {'cmd': banner_cmd, 'input': '\n'.join(banner_input)}
|
||||
banner_cmd = None
|
||||
commands.append(command)
|
||||
else:
|
||||
banner_input.append(command)
|
||||
continue
|
||||
else:
|
||||
commands.append(command)
|
||||
reply = self.send_request('show hostname | json')
|
||||
data = json.loads(reply)
|
||||
|
||||
try:
|
||||
response = self.send_request(commands)
|
||||
except Exception:
|
||||
commands = ['configure session %s' % session, 'abort']
|
||||
response = self.send_request(commands, output='text')
|
||||
raise
|
||||
device_info['network_os_hostname'] = data['hostname']
|
||||
|
||||
commands = ['configure session %s' % session, 'show session-config diffs']
|
||||
if commit:
|
||||
commands.append('commit')
|
||||
else:
|
||||
commands.append('abort')
|
||||
self._device_info = device_info
|
||||
return self._device_info
|
||||
|
||||
response = self.send_request(commands, output='text')
|
||||
diff = response[1].strip()
|
||||
if diff:
|
||||
result['diff'] = diff
|
||||
def get_device_operations(self):
|
||||
return {
|
||||
'supports_diff_replace': True,
|
||||
'supports_commit': bool(self.supports_sessions),
|
||||
'supports_rollback': False,
|
||||
'supports_defaults': False,
|
||||
'supports_onbox_diff': bool(self.supports_sessions),
|
||||
'supports_commit_comment': False,
|
||||
'supports_multiline_delimiter': False,
|
||||
'supports_diff_match': True,
|
||||
'supports_diff_ignore_lines': True,
|
||||
'supports_generate_diff': not bool(self.supports_sessions),
|
||||
'supports_replace': bool(self.supports_sessions),
|
||||
}
|
||||
|
||||
return result
|
||||
def get_capabilities(self):
|
||||
result = {}
|
||||
result['rpc'] = []
|
||||
result['device_info'] = self.get_device_info()
|
||||
result['device_operations'] = self.get_device_operations()
|
||||
result.update(OPTIONS)
|
||||
result['network_api'] = 'eapi'
|
||||
|
||||
def run_commands(self, commands, check_rc=True):
|
||||
"""Runs list of commands on remote device and returns results
|
||||
"""
|
||||
output = None
|
||||
queue = list()
|
||||
responses = list()
|
||||
|
||||
def run_queue(queue, output):
|
||||
try:
|
||||
response = to_list(self.send_request(queue, output=output))
|
||||
except Exception as exc:
|
||||
if check_rc:
|
||||
raise
|
||||
return to_text(exc)
|
||||
|
||||
if output == 'json':
|
||||
response = [json.loads(item) for item in response]
|
||||
return response
|
||||
|
||||
for item in to_list(commands):
|
||||
cmd_output = 'text'
|
||||
if isinstance(item, dict):
|
||||
command = item['command']
|
||||
if 'output' in item:
|
||||
cmd_output = item['output']
|
||||
else:
|
||||
command = item
|
||||
|
||||
# Emulate '| json' from CLI
|
||||
if command.endswith('| json'):
|
||||
command = command.rsplit('|', 1)[0]
|
||||
cmd_output = 'json'
|
||||
|
||||
if output and output != cmd_output:
|
||||
responses.extend(run_queue(queue, output))
|
||||
queue = list()
|
||||
|
||||
output = cmd_output
|
||||
queue.append(command)
|
||||
|
||||
if queue:
|
||||
responses.extend(run_queue(queue, output))
|
||||
|
||||
return responses
|
||||
|
||||
def load_config(self, config, commit=False, replace=False):
|
||||
"""Loads the configuration onto the remote devices
|
||||
|
||||
If the device doesn't support configuration sessions, this will
|
||||
fallback to using configure() to load the commands. If that happens,
|
||||
there will be no returned diff or session values
|
||||
"""
|
||||
return self.edit_config(config, commit, replace)
|
||||
return json.dumps(result)
|
||||
|
||||
|
||||
def handle_response(response):
|
||||
|
@ -170,6 +157,7 @@ def handle_response(response):
|
|||
raise ConnectionError(error_text, code=error['code'])
|
||||
|
||||
results = []
|
||||
|
||||
for result in response['result']:
|
||||
if 'messages' in result:
|
||||
results.append(result['messages'][0])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue