diff options
Diffstat (limited to 'lib/ansible/plugins')
-rw-r--r-- | lib/ansible/plugins/action/eos.py | 134 | ||||
-rw-r--r-- | lib/ansible/plugins/cliconf/eos.py | 306 | ||||
-rw-r--r-- | lib/ansible/plugins/doc_fragments/eos.py | 115 | ||||
-rw-r--r-- | lib/ansible/plugins/httpapi/eos.py | 171 | ||||
-rw-r--r-- | lib/ansible/plugins/terminal/eos.py | 92 |
5 files changed, 0 insertions, 818 deletions
diff --git a/lib/ansible/plugins/action/eos.py b/lib/ansible/plugins/action/eos.py deleted file mode 100644 index 1b76e1826f..0000000000 --- a/lib/ansible/plugins/action/eos.py +++ /dev/null @@ -1,134 +0,0 @@ -# -# (c) 2016 Red Hat Inc. -# -# 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 - -import sys -import copy - -from ansible import constants as C -from ansible.module_utils.network.eos.eos import eos_provider_spec -from ansible.plugins.action.network import ActionModule as ActionNetworkModule -from ansible.module_utils.network.common.utils import load_provider -from ansible.utils.display import Display - -display = Display() - - -class ActionModule(ActionNetworkModule): - - def run(self, tmp=None, task_vars=None): - del tmp # tmp no longer has any effect - - module_name = self._task.action.split('.')[-1] - self._config_module = True if module_name == 'eos_config' else False - persistent_connection = self._play_context.connection.split('.')[-1] - warnings = [] - - if persistent_connection in ('network_cli', 'httpapi'): - provider = self._task.args.get('provider', {}) - if any(provider.values()): - display.warning('provider is unnecessary when using %s and will be ignored' % self._play_context.connection) - del self._task.args['provider'] - if self._task.args.get('transport'): - display.warning('transport is unnecessary when using %s and will be ignored' % self._play_context.connection) - del self._task.args['transport'] - elif self._play_context.connection == 'local': - provider = load_provider(eos_provider_spec, self._task.args) - transport = provider['transport'] or 'cli' - - display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) - - if transport == 'cli': - pc = copy.deepcopy(self._play_context) - pc.connection = 'ansible.netcommon.network_cli' - pc.network_os = 'arista.eos.eos' - pc.remote_addr = provider['host'] or self._play_context.remote_addr - pc.port = int(provider['port'] or self._play_context.port or 22) - pc.remote_user = provider['username'] or self._play_context.connection_user - pc.password = provider['password'] or self._play_context.password - pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file - pc.become = provider['authorize'] or False - if pc.become: - pc.become_method = 'enable' - pc.become_pass = provider['auth_pass'] - - connection = self._shared_loader_obj.connection_loader.get('ansible.netcommon.persistent', pc, sys.stdin, - task_uuid=self._task._uuid) - - # TODO: Remove below code after ansible minimal is cut out - if connection is None: - pc.connection = 'network_cli' - pc.network_os = 'eos' - connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin, task_uuid=self._task._uuid) - - display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) - - command_timeout = int(provider['timeout']) if provider['timeout'] else connection.get_option('persistent_command_timeout') - connection.set_options(direct={'persistent_command_timeout': command_timeout}) - - socket_path = connection.run() - display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) - if not socket_path: - return {'failed': True, - 'msg': 'unable to open shell. Please see: ' + - 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} - - task_vars['ansible_socket'] = socket_path - warnings.append(['connection local support for this module is deprecated and will be removed in version 2.14,' - ' use connection %s' % pc.connection]) - else: - self._task.args['provider'] = ActionModule.eapi_implementation(provider, self._play_context) - warnings.append(['connection local support for this module is deprecated and will be removed in version 2.14,' - ' use connection either httpapi or ansible.netcommon.httpapi (whichever is applicable)']) - else: - return {'failed': True, 'msg': 'Connection type %s is not valid for this module' % self._play_context.connection} - - result = super(ActionModule, self).run(task_vars=task_vars) - if warnings: - if 'warnings' in result: - result['warnings'].extend(warnings) - else: - result['warnings'] = warnings - return result - - @staticmethod - def eapi_implementation(provider, play_context): - provider['transport'] = 'eapi' - - if provider.get('host') is None: - provider['host'] = play_context.remote_addr - - if provider.get('port') is None: - default_port = 443 if provider['use_ssl'] else 80 - provider['port'] = int(play_context.port or default_port) - - if provider.get('timeout') is None: - provider['timeout'] = C.PERSISTENT_COMMAND_TIMEOUT - - if provider.get('username') is None: - provider['username'] = play_context.connection_user - - if provider.get('password') is None: - provider['password'] = play_context.password - - if provider.get('authorize') is None: - provider['authorize'] = False - - return provider diff --git a/lib/ansible/plugins/cliconf/eos.py b/lib/ansible/plugins/cliconf/eos.py deleted file mode 100644 index 9141e1d7f3..0000000000 --- a/lib/ansible/plugins/cliconf/eos.py +++ /dev/null @@ -1,306 +0,0 @@ -# -# (c) 2017 Red Hat Inc. -# -# 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 - -DOCUMENTATION = """ ---- -author: Ansible Networking Team -cliconf: eos -short_description: Use eos cliconf to run command on Arista EOS platform -description: - - This eos plugin provides low level abstraction apis for - sending and receiving CLI commands from Arista EOS network devices. -version_added: "2.4" -options: - eos_use_sessions: - type: boolean - default: yes - 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.7' -""" - -import json -import time -import re - -from ansible.errors import AnsibleConnectionFailure -from ansible.module_utils._text import to_text -from ansible.module_utils.common._collections_compat import Mapping -from ansible.module_utils.network.common.utils import to_list -from ansible.module_utils.network.common.config import NetworkConfig, dumps -from ansible.plugins.cliconf import CliconfBase, enable_mode - - -class Cliconf(CliconfBase): - - def __init__(self, *args, **kwargs): - super(Cliconf, self).__init__(*args, **kwargs) - self._session_support = None - - @enable_mode - def get_config(self, source='running', format='text', flags=None): - options_values = self.get_option_values() - if format not in options_values['format']: - raise ValueError("'format' value %s is invalid. Valid values are %s" % (format, ','.join(options_values['format']))) - - lookup = {'running': 'running-config', 'startup': 'startup-config'} - if source not in lookup: - raise ValueError("fetching configuration from %s is not supported" % source) - - cmd = 'show %s ' % lookup[source] - if format and format != 'text': - cmd += '| %s ' % format - - cmd += ' '.join(to_list(flags)) - cmd = cmd.strip() - return self.send_command(cmd) - - @enable_mode - def edit_config(self, candidate=None, commit=True, replace=None, comment=None): - - operations = self.get_device_operations() - self.check_edit_config_capability(operations, candidate, commit, replace, comment) - - if (commit is False) and (not self.supports_sessions()): - raise ValueError('check mode is not supported without configuration session') - - resp = {} - session = None - if self.supports_sessions(): - session = 'ansible_%s' % int(time.time()) - resp.update({'session': session}) - self.send_command('configure session %s' % session) - if replace: - self.send_command('rollback clean-config') - else: - self.send_command('configure') - - results = [] - requests = [] - multiline = False - for line in to_list(candidate): - if not isinstance(line, Mapping): - line = {'command': line} - - cmd = line['command'] - if cmd == 'end': - continue - elif cmd.startswith('banner') or multiline: - multiline = True - elif cmd == 'EOF' and multiline: - multiline = False - - if multiline: - line['sendonly'] = True - - if cmd != 'end' and cmd[0] != '!': - try: - results.append(self.send_command(**line)) - requests.append(cmd) - except AnsibleConnectionFailure as e: - self.discard_changes(session) - raise AnsibleConnectionFailure(e.message) - - resp['request'] = requests - resp['response'] = results - if self.supports_sessions(): - out = self.send_command('show session-config diffs') - if out: - resp['diff'] = out.strip() - - if commit: - self.commit() - else: - self.discard_changes(session) - else: - self.send_command('end') - return resp - - def get(self, command, prompt=None, answer=None, sendonly=False, output=None, newline=True, check_all=False): - if output: - command = self._get_command_with_output(command, output) - return self.send_command(command=command, prompt=prompt, answer=answer, sendonly=sendonly, newline=newline, check_all=check_all) - - def commit(self): - self.send_command('commit') - - def discard_changes(self, session=None): - commands = ['end'] - if self.supports_sessions(): - # to close session gracefully execute abort in top level session prompt. - commands.extend(['configure session %s' % session, 'abort']) - - for cmd in commands: - self.send_command(cmd) - - def run_commands(self, commands=None, check_rc=True): - if commands is None: - raise ValueError("'commands' value is required") - responses = list() - for cmd in to_list(commands): - if not isinstance(cmd, Mapping): - cmd = {'command': cmd} - - output = cmd.pop('output', None) - if output: - cmd['command'] = self._get_command_with_output(cmd['command'], output) - - try: - out = self.send_command(**cmd) - except AnsibleConnectionFailure as e: - if check_rc: - raise - out = getattr(e, 'err', e) - out = to_text(out, errors='surrogate_or_strict') - - if out is not None: - try: - out = json.loads(out) - except ValueError: - out = out.strip() - - responses.append(out) - return responses - - def get_diff(self, candidate=None, running=None, diff_match='line', diff_ignore_lines=None, path=None, diff_replace='line'): - diff = {} - device_operations = self.get_device_operations() - option_values = self.get_option_values() - - if candidate is None and device_operations['supports_generate_diff']: - raise ValueError("candidate configuration is required to generate diff") - - if diff_match not in option_values['diff_match']: - raise ValueError("'match' value %s in invalid, valid values are %s" % (diff_match, ', '.join(option_values['diff_match']))) - - if diff_replace not in option_values['diff_replace']: - raise ValueError("'replace' value %s in invalid, valid values are %s" % (diff_replace, ', '.join(option_values['diff_replace']))) - - # prepare candidate configuration - candidate_obj = NetworkConfig(indent=3) - candidate_obj.load(candidate) - - if running and diff_match != 'none' and diff_replace != 'config': - # running configuration - running_obj = NetworkConfig(indent=3, contents=running, ignore_lines=diff_ignore_lines) - configdiffobjs = candidate_obj.difference(running_obj, path=path, match=diff_match, replace=diff_replace) - - else: - configdiffobjs = candidate_obj.items - - diff['config_diff'] = dumps(configdiffobjs, 'commands') if configdiffobjs else '' - return diff - - def supports_sessions(self): - if not self.get_option('eos_use_sessions'): - self._session_support = False - else: - if self._session_support: - return self._session_support - - try: - self.get('show configuration sessions') - self._session_support = True - except AnsibleConnectionFailure: - self._session_support = False - - return self._session_support - - def get_device_info(self): - device_info = {} - - device_info['network_os'] = 'eos' - reply = self.get('show version | json') - data = json.loads(reply) - - device_info['network_os_version'] = data['version'] - device_info['network_os_model'] = data['modelName'] - - reply = self.get('show hostname | json') - data = json.loads(reply) - - device_info['network_os_hostname'] = data['hostname'] - - try: - reply = self.get('bash timeout 5 cat /mnt/flash/boot-config') - - match = re.search(r'SWI=(.+)$', reply, re.M) - if match: - device_info['network_os_image'] = match.group(1) - except AnsibleConnectionFailure: - # This requires enable mode to run - self._connection.queue_message('vvv', "Unable to gather network_os_image without enable mode") - - return device_info - - 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()), - } - - def get_option_values(self): - return { - 'format': ['text', 'json'], - 'diff_match': ['line', 'strict', 'exact', 'none'], - 'diff_replace': ['line', 'block', 'config'], - 'output': ['text', 'json'] - } - - def get_capabilities(self): - result = super(Cliconf, self).get_capabilities() - result['rpc'] += ['commit', 'discard_changes', 'get_diff', 'run_commands', 'supports_sessions'] - result['device_operations'] = self.get_device_operations() - result.update(self.get_option_values()) - - return json.dumps(result) - - def set_cli_prompt_context(self): - """ - Make sure we are in the operational cli mode - :return: None - """ - if self._connection.connected: - self._update_cli_prompt_context(config_context='(config', exit_command='abort') - - def _get_command_with_output(self, command, output): - options_values = self.get_option_values() - if output not in options_values['output']: - raise ValueError("'output' value %s is invalid. Valid values are %s" % (output, ','.join(options_values['output']))) - - if output == 'json' and not command.endswith('| json'): - cmd = '%s | json' % command - else: - cmd = command - return cmd diff --git a/lib/ansible/plugins/doc_fragments/eos.py b/lib/ansible/plugins/doc_fragments/eos.py deleted file mode 100644 index d6fbc1caf5..0000000000 --- a/lib/ansible/plugins/doc_fragments/eos.py +++ /dev/null @@ -1,115 +0,0 @@ -# -*- coding: utf-8 -*- - -# Copyright: (c) 2015, Peter Sprygada <psprygada@ansible.com> -# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) - - -class ModuleDocFragment(object): - - # Standard files documentation fragment - DOCUMENTATION = r''' -options: - provider: - description: - - B(Deprecated) - - "Starting with Ansible 2.5 we recommend using C(connection: network_cli)." - - This option is only required if you are using eAPI. - - For more information please see the L(EOS Platform Options guide, ../network/user_guide/platform_eos.html). - - HORIZONTALLINE - - A dict object containing connection details. - type: dict - suboptions: - host: - description: - - Specifies the DNS host name or address for connecting to the remote - device over the specified transport. The value of host is used as - the destination address for the transport. - type: str - required: true - port: - description: - - Specifies the port to use when building the connection to the remote - device. This value applies to either I(cli) or I(eapi). - - The port value will default to the appropriate transport common port - if none is provided in the task (cli=22, http=80, https=443). - type: int - default: 0 - username: - description: - - Configures the username to use to authenticate the connection to - the remote device. This value is used to authenticate - either the CLI login or the eAPI authentication depending on which - transport is used. If the value is not specified in the task, the - value of environment variable C(ANSIBLE_NET_USERNAME) will be used instead. - type: str - password: - description: - - Specifies the password to use to authenticate the connection to - the remote device. This is a common argument used for either I(cli) - or I(eapi) transports. If the value is not specified in the task, the - value of environment variable C(ANSIBLE_NET_PASSWORD) will be used instead. - type: str - timeout: - description: - - Specifies the timeout in seconds for communicating with the network device - for either connecting or sending commands. If the timeout is - exceeded before the operation is completed, the module will error. - type: int - ssh_keyfile: - description: - - Specifies the SSH keyfile to use to authenticate the connection to - the remote device. This argument is only used for I(cli) transports. - If the value is not specified in the task, the value of environment - variable C(ANSIBLE_NET_SSH_KEYFILE) will be used instead. - type: path - authorize: - description: - - Instructs the module to enter privileged mode on the remote device - before sending any commands. If not specified, the device will - attempt to execute all commands in non-privileged mode. If the value - is not specified in the task, the value of environment variable - C(ANSIBLE_NET_AUTHORIZE) will be used instead. - type: bool - default: no - auth_pass: - description: - - Specifies the password to use if required to enter privileged mode - on the remote device. If I(authorize) is false, then this argument - does nothing. If the value is not specified in the task, the value of - environment variable C(ANSIBLE_NET_AUTH_PASS) will be used instead. - type: str - transport: - description: - - Configures the transport connection to use when connecting to the - remote device. - required: true - type: str - choices: [ cli, eapi ] - default: cli - use_ssl: - description: - - Configures the I(transport) to use SSL if set to C(yes) only when the - C(transport=eapi). If the transport - argument is not eapi, this value is ignored. - type: bool - default: yes - validate_certs: - description: - - If C(no), SSL certificates will not be validated. This should only be used - on personally controlled sites using self-signed certificates. If the transport - argument is not eapi, this value is ignored. - type: bool - default: true - use_proxy: - description: - - If C(no), the environment variables C(http_proxy) and C(https_proxy) will be ignored. - type: bool - default: yes - version_added: "2.5" - -notes: - - For information on using CLI, eAPI and privileged mode see the :ref:`EOS Platform Options guide <eos_platform_options>` - - For more information on using Ansible to manage network devices see the :ref:`Ansible Network Guide <network_guide>` - - For more information on using Ansible to manage Arista EOS devices see the `Arista integration page <https://www.ansible.com/ansible-arista-networks>`_. - -''' diff --git a/lib/ansible/plugins/httpapi/eos.py b/lib/ansible/plugins/httpapi/eos.py deleted file mode 100644 index 325c31ede6..0000000000 --- a/lib/ansible/plugins/httpapi/eos.py +++ /dev/null @@ -1,171 +0,0 @@ -# (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 - -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 - -from ansible.module_utils._text import to_text -from ansible.module_utils.connection import ConnectionError -from ansible.module_utils.network.common.utils import to_list -from ansible.plugins.httpapi import HttpApiBase - - -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 - - 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) - become = self._become - if become: - self.connection.queue_message('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, response_data = self.connection.send('/command-api', request, headers=headers, method='POST') - - try: - response_data = json.loads(to_text(response_data.getvalue())) - except ValueError: - raise ConnectionError('Response was not valid JSON, got {0}'.format( - to_text(response_data.getvalue()) - )) - - results = handle_response(response_data) - - if become: - results = results[1:] - if len(results) == 1: - results = results[0] - - return results - - def get_device_info(self): - if self._device_info: - return self._device_info - - device_info = {} - - device_info['network_os'] = 'eos' - reply = self.send_request('show version', output='json') - data = json.loads(reply) - - device_info['network_os_version'] = data['version'] - device_info['network_os_model'] = data['modelName'] - - reply = self.send_request('show hostname | json') - data = json.loads(reply) - - device_info['network_os_hostname'] = data['hostname'] - - self._device_info = device_info - return self._device_info - - 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()), - } - - 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' - - return json.dumps(result) - - -def handle_response(response): - if 'error' in response: - error = response['error'] - - error_text = [] - for data in error['data']: - error_text.extend(data.get('errors', [])) - error_text = '\n'.join(error_text) or error['message'] - - raise ConnectionError(error_text, 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)) diff --git a/lib/ansible/plugins/terminal/eos.py b/lib/ansible/plugins/terminal/eos.py deleted file mode 100644 index 799a434c35..0000000000 --- a/lib/ansible/plugins/terminal/eos.py +++ /dev/null @@ -1,92 +0,0 @@ -# -# (c) 2016 Red Hat Inc. -# -# 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 - -import re -import json - -from ansible.plugins.terminal import TerminalBase -from ansible.errors import AnsibleConnectionFailure -from ansible.module_utils._text import to_bytes, to_text - - -class TerminalModule(TerminalBase): - - terminal_stdout_re = [ - re.compile(br"[\r\n]?[\w+\-\.:\/\[\]]+(?:\([^\)]+\)){,3}(?:>|#) ?$"), - re.compile(br"\[\w+\@[\w\-\.]+(?: [^\]])\] ?[>#\$] ?$") - ] - - terminal_stderr_re = [ - re.compile(br"% ?Error"), - # re.compile(br"^% \w+", re.M), - re.compile(br"% User not present"), - re.compile(br"% ?Bad secret"), - re.compile(br"invalid input", re.I), - re.compile(br"(?:incomplete|ambiguous) command", re.I), - re.compile(br"connection timed out", re.I), - # Strings like this regarding VLANs are not errors - re.compile(br"[^\r\n]+ not found(?! in current VLAN)", re.I), - re.compile(br"'[^']' +returned error code: ?\d+"), - re.compile(br"[^\r\n](?<! shell )\/bin\/(?:ba)?sh"), - re.compile(br"% More than \d+ OSPF instance", re.I), - re.compile(br"% Subnet [0-9a-f.:/]+ overlaps", re.I), - re.compile(br"Maximum number of pending sessions has been reached"), - re.compile(br"% Prefix length must be less than"), - ] - - def on_open_shell(self): - try: - for cmd in (b'terminal length 0', b'terminal width 512'): - self._exec_cli_command(cmd) - except AnsibleConnectionFailure: - raise AnsibleConnectionFailure('unable to set terminal parameters') - - def on_become(self, passwd=None): - if self._get_prompt().endswith(b'#'): - return - - cmd = {u'command': u'enable'} - if passwd: - cmd[u'prompt'] = to_text(r"[\r\n]?password: $", errors='surrogate_or_strict') - cmd[u'answer'] = passwd - cmd[u'prompt_retry_check'] = True - - try: - self._exec_cli_command(to_bytes(json.dumps(cmd), errors='surrogate_or_strict')) - prompt = self._get_prompt() - if prompt is None or not prompt.endswith(b'#'): - raise AnsibleConnectionFailure('failed to elevate privilege to enable mode still at prompt [%s]' % prompt) - except AnsibleConnectionFailure as e: - prompt = self._get_prompt() - raise AnsibleConnectionFailure('unable to elevate privilege to enable mode, at prompt [%s] with error: %s' % (prompt, e.message)) - - def on_unbecome(self): - prompt = self._get_prompt() - if prompt is None: - # if prompt is None most likely the terminal is hung up at a prompt - return - - if b'(config' in prompt: - self._exec_cli_command(b'end') - self._exec_cli_command(b'disable') - - elif prompt.endswith(b'#'): - self._exec_cli_command(b'disable') |