From 40d29936a4dbeb15f9970f5aebdf0e795124cfee Mon Sep 17 00:00:00 2001 From: Brian Coca Date: Fri, 11 Aug 2017 22:46:26 -0400 Subject: [PATCH] telnet action plugin (#27983) * draft telnet action plugin docs in module * updated per feedback * fixed imports * pep8 fixes * added meta import even though its useless --- lib/ansible/modules/commands/telnet.py | 75 ++++++++++++++++++++++++ lib/ansible/plugins/action/telnet.py | 81 ++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 lib/ansible/modules/commands/telnet.py create mode 100644 lib/ansible/plugins/action/telnet.py diff --git a/lib/ansible/modules/commands/telnet.py b/lib/ansible/modules/commands/telnet.py new file mode 100644 index 0000000000..3b9f697a9c --- /dev/null +++ b/lib/ansible/modules/commands/telnet.py @@ -0,0 +1,75 @@ +# this is a virtual module that is entirely implemented server side +# Copyright: Ansible Project +# 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 + +ANSIBLE_METADATA = {'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: telnet +short_description: Executes a low-down and dirty telnet command +version_added: 2.4 +description: + - Executes a low-down and dirty telnet command, not going through the module subsystem. + - This is mostly to be used for enabling ssh on devices that only have telnet enabled by default. +options: + commands: + description: + - List of commands to be executed in the telnet session. + required: True + host: + description: + - The host/target on which to execute the command + required: False + default: remote_addr + user: + description: + - The user for login + required: False + default: remote_user + password: + description: + - The password for login + port: + description: + - Remote port to use + default: 23 + timeout: + description: + - timeout for remote operations + default: 120 + command: + description: + - Command to execute in telnet session + required: True + pause: + description: + - Seconds to pause between each command issued + required: False + default: 1 +notes: + - The C(environment) keyword does not work with this task +author: + - Ansible Core Team +''' + +EXAMPLES = ''' +- name: Force ssh on IOS + telnet: + command: transport input ssh + user: cisco + password: cisco +''' + +RETURN = ''' +output: + description: output of each command is an element in this list + type: list + returned: always + sample: [ 'success', 'success', '', 'warning .. something' ] +''' diff --git a/lib/ansible/plugins/action/telnet.py b/lib/ansible/plugins/action/telnet.py new file mode 100644 index 0000000000..765ea897bc --- /dev/null +++ b/lib/ansible/plugins/action/telnet.py @@ -0,0 +1,81 @@ +# (c) 2017, Ansible Project +# +# 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 telnetlib +from time import sleep + +from ansible.module_utils._text import to_native +from ansible.module_utils.six import text_type +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + TRANSFERS_FILES = False + + def run(self, tmp=None, task_vars=None): + + if self._task.environment and any(self._task.environment): + self._display.warning('The telnet task does not support the environment keyword') + + result = super(ActionModule, self).run(tmp, task_vars) + + if self._play_context.check_mode: + # in --check mode, always skip this module execution + result['skipped'] = True + result['msg'] = 'The telnet task does not support check mode' + else: + result['changed'] = True + result['failed'] = False + + host = self._task.args.get('host', self._play_context.remote_addr) + user = self._task.args.get('user', self._play_context.remote_user) + password = self._task.args.get('password', self._play_context.password) + + # FIXME, default to play_context? + port = self._task.args.get('port', '23') + timeout = self._task.args.get('timeout', 120) + pause = self._task.args.get('pause', 1) + + login_prompt = self._task.args.get('login_prompt', "login: ") + password_prompt = self._task.args.get('password_prompt', "Password: ") + commands = self._task.args.get('command') + + if isinstance(commands, text_type): + commands = commands.split(',') + + if isinstance(commands, list) and commands: + + tn = telnetlib.Telnet(host, port, timeout) + + output = [] + try: + tn.read_until(login_prompt) + tn.write('%s\n' % user) + + if password: + tn.read_until(password_prompt) + tn.write('%s\n' % password) + + for cmd in commands: + tn.write(cmd) + output.append(tn.read_until('')) + sleep(pause) + + tn.write("exit\n") + + except EOFError as e: + result['failed'] = True + result['msg'] = 'Telnet action failed: %s' % to_native(e) + finally: + if tn: + tn.close() + result['output'] = output + else: + result['failed'] = True + result['msg'] = 'Telnet requries a command to execute' + + return result