community.general/lib/ansible/plugins/httpapi/eos.py

177 lines
5.6 KiB
Python

# (c) 2018 Red Hat Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
import time
from ansible.module_utils._text import to_text
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.connection import ConnectionError
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
class HttpApi:
def __init__(self, connection):
self.connection = connection
self._become = False
def send_request(self, data, **message_kwargs):
data = to_list(data)
if self._become:
display.vvvv('firing event: on_become')
data.insert(0, {"cmd": "enable", "input": self._become_pass})
output = message_kwargs.get('output', 'text')
request = request_builder(data, output)
headers = {'Content-Type': 'application/json-rpc'}
response = self.connection.send('/command-api', request, headers=headers, method='POST')
response_text = to_text(response.read())
try:
response = json.loads(response_text)
except ValueError:
raise ConnectionError('Response was not valid JSON, got {0}'.format(response_text))
results = handle_response(response)
if self._become:
results = results[1:]
if len(results) == 1:
results = results[0]
return results
def get_prompt(self):
# Fake a prompt for @enable_mode
if self._become:
return '#'
else:
return '>'
def set_become(self, play_context):
self._become = play_context.become
self._become_pass = getattr(play_context, 'become_pass') or ''
# Imported from module_utils
def edit_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
"""
session = 'ansible_%s' % int(time.time())
result = {'session': session}
banner_cmd = None
banner_input = []
commands = ['configure session %s' % session]
if replace:
commands.append('rollback clean-config')
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)
response = self.send_request(commands)
commands = ['configure session %s' % session, 'show session-config diffs']
if commit:
commands.append('commit')
else:
commands.append('abort')
response = self.send_request(commands, output='text')
diff = response[1].strip()
if diff:
result['diff'] = diff
return result
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):
response = to_list(self.send_request(queue, output=output))
if output == 'json':
response = [json.loads(item) for item in response]
return response
for item in to_list(commands):
cmd_output = None
if isinstance(item, dict):
command = item['command']
if command.endswith('| json'):
command = command.replace('| json', '')
cmd_output = 'json'
elif 'output' in item:
cmd_output = item['output']
else:
command = item
cmd_output = 'json'
if output and output != cmd_output:
responses.extend(run_queue(queue, output))
queue = list()
output = cmd_output or 'json'
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)
def handle_response(response):
if 'error' in response:
error = response['error']
raise ConnectionError(error['message'], code=error['code'])
results = []
for result in response['result']:
if 'messages' in result:
results.append(result['messages'][0])
elif 'output' in result:
results.append(result['output'].strip())
else:
results.append(json.dumps(result))
return results
def request_builder(commands, output, reqid=None):
params = dict(version=1, cmds=commands, format=output)
return json.dumps(dict(jsonrpc='2.0', id=reqid, method='runCmds', params=params))