mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-02 14:40:19 -07:00
HTTP(S) API connection plugin (#39224)
* HTTPAPI connection * Punt run_commands to cliconf or httpapi * Fake enable_mode on eapi * Pull changes to nxos * Move load_config to edit_config for future-preparedness * Don't fail on lldp disabled * Re-enable check_rc on nxos' run_commands * Reorganize nxos httpapi plugin for compatibility * draft docs for connection: httpapi * restores docs for connection:local for eapi * Add _remote_is_local to httpapi
This commit is contained in:
parent
cc61c86049
commit
e9d7fa0418
277 changed files with 1325 additions and 1676 deletions
|
@ -20,15 +20,37 @@ from __future__ import (absolute_import, division, print_function)
|
|||
__metaclass__ = type
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from itertools import chain
|
||||
|
||||
from ansible.module_utils._text import to_bytes
|
||||
from ansible.module_utils.network.common.utils import to_list
|
||||
from ansible.plugins.cliconf import CliconfBase, enable_mode
|
||||
from ansible.plugins.connection.network_cli import Connection as NetworkCli
|
||||
|
||||
|
||||
class Cliconf(CliconfBase):
|
||||
|
||||
def send_command(self, command, prompt=None, answer=None, sendonly=False, newline=True, prompt_retry_check=False):
|
||||
"""Executes a cli command and returns the results
|
||||
This method will execute the CLI command on the connection and return
|
||||
the results to the caller. The command output will be returned as a
|
||||
string
|
||||
"""
|
||||
kwargs = {'command': to_bytes(command), 'sendonly': sendonly,
|
||||
'newline': newline, 'prompt_retry_check': prompt_retry_check}
|
||||
if prompt is not None:
|
||||
kwargs['prompt'] = to_bytes(prompt)
|
||||
if answer is not None:
|
||||
kwargs['answer'] = to_bytes(answer)
|
||||
|
||||
if isinstance(self._connection, NetworkCli):
|
||||
resp = self._connection.send(**kwargs)
|
||||
else:
|
||||
resp = self._connection.send_request(command, **kwargs)
|
||||
return resp
|
||||
|
||||
def get_device_info(self):
|
||||
device_info = {}
|
||||
|
||||
|
@ -74,3 +96,72 @@ class Cliconf(CliconfBase):
|
|||
result['network_api'] = 'cliconf'
|
||||
result['device_info'] = self.get_device_info()
|
||||
return json.dumps(result)
|
||||
|
||||
# Imported from module_utils
|
||||
def close_session(self, session):
|
||||
# to close session gracefully execute abort in top level session prompt.
|
||||
self.get('end')
|
||||
self.get('configure session %s' % session)
|
||||
self.get('abort')
|
||||
|
||||
def run_commands(self, commands, check_rc=True):
|
||||
"""Run list of commands on remote device and return results
|
||||
"""
|
||||
responses = list()
|
||||
multiline = False
|
||||
|
||||
for cmd in to_list(commands):
|
||||
if isinstance(cmd, dict):
|
||||
command = cmd['command']
|
||||
prompt = cmd['prompt']
|
||||
answer = cmd['answer']
|
||||
else:
|
||||
command = cmd
|
||||
prompt = None
|
||||
answer = None
|
||||
|
||||
if command == 'end':
|
||||
continue
|
||||
elif command.startswith('banner') or multiline:
|
||||
multiline = True
|
||||
elif command == 'EOF' and multiline:
|
||||
multiline = False
|
||||
|
||||
out = self.get(command, prompt, answer, multiline)
|
||||
|
||||
if out is not None:
|
||||
try:
|
||||
out = json.loads(out)
|
||||
except ValueError:
|
||||
out = str(out).strip()
|
||||
|
||||
responses.append(out)
|
||||
|
||||
return responses
|
||||
|
||||
def load_config(self, commands, commit=False, replace=False):
|
||||
"""Loads the config commands onto the remote device
|
||||
"""
|
||||
session = 'ansible_%s' % int(time.time())
|
||||
result = {'session': session}
|
||||
|
||||
self.get('configure session %s' % session)
|
||||
if replace:
|
||||
self.get('rollback clean-config')
|
||||
|
||||
try:
|
||||
self.run_commands(commands)
|
||||
except ConnectionError:
|
||||
self.close_session(session)
|
||||
raise
|
||||
|
||||
out = self.get('show session-config diffs')
|
||||
if out:
|
||||
result['diff'] = out.strip()
|
||||
|
||||
if commit:
|
||||
self.get('commit')
|
||||
else:
|
||||
self.close_session(session)
|
||||
|
||||
return result
|
||||
|
|
|
@ -23,12 +23,33 @@ import json
|
|||
|
||||
from itertools import chain
|
||||
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
from ansible.module_utils.network.common.utils import to_list
|
||||
from ansible.plugins.cliconf import CliconfBase
|
||||
from ansible.plugins.connection.network_cli import Connection as NetworkCli
|
||||
|
||||
|
||||
class Cliconf(CliconfBase):
|
||||
|
||||
def send_command(self, command, prompt=None, answer=None, sendonly=False, newline=True, prompt_retry_check=False):
|
||||
"""Executes a cli command and returns the results
|
||||
This method will execute the CLI command on the connection and return
|
||||
the results to the caller. The command output will be returned as a
|
||||
string
|
||||
"""
|
||||
kwargs = {'command': to_bytes(command), 'sendonly': sendonly,
|
||||
'newline': newline, 'prompt_retry_check': prompt_retry_check}
|
||||
if prompt is not None:
|
||||
kwargs['prompt'] = to_bytes(prompt)
|
||||
if answer is not None:
|
||||
kwargs['answer'] = to_bytes(answer)
|
||||
|
||||
if isinstance(self._connection, NetworkCli):
|
||||
resp = self._connection.send(**kwargs)
|
||||
else:
|
||||
resp = self._connection.send_request(command, **kwargs)
|
||||
return resp
|
||||
|
||||
def get_device_info(self):
|
||||
device_info = {}
|
||||
|
||||
|
@ -76,3 +97,37 @@ class Cliconf(CliconfBase):
|
|||
result['network_api'] = 'cliconf'
|
||||
result['device_info'] = self.get_device_info()
|
||||
return json.dumps(result)
|
||||
|
||||
# Migrated from module_utils
|
||||
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 item['command'].endswith('| json'):
|
||||
cmd = '%s | json' % item['command']
|
||||
elif item['output'] == 'text' and item['command'].endswith('| json'):
|
||||
cmd = item['command'].rsplit('|', 1)[0]
|
||||
else:
|
||||
cmd = item['command']
|
||||
|
||||
try:
|
||||
out = self.get(cmd)
|
||||
except ConnectionError as e:
|
||||
if check_rc:
|
||||
raise
|
||||
out = e
|
||||
|
||||
try:
|
||||
out = to_text(out, errors='surrogate_or_strict').strip()
|
||||
except UnicodeError:
|
||||
raise ConnectionError(msg=u'Failed to decode output from %s: %s' % (cmd, to_text(out)))
|
||||
|
||||
try:
|
||||
out = json.loads(out)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
responses.append(out)
|
||||
return responses
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue