enabled initial support for password prompt on become
- moved check prompt/password functions to connection, make more senes there - TODO: consider moving make_become to connection from connection_info - removed executable param that was never overriden outside of connection info
This commit is contained in:
parent
bac35ae773
commit
580993fef7
5 changed files with 37 additions and 38 deletions
|
@ -24,7 +24,6 @@ __metaclass__ = type
|
|||
import pipes
|
||||
import random
|
||||
import re
|
||||
import gettext
|
||||
|
||||
from ansible import constants as C
|
||||
from ansible.template import Templar
|
||||
|
@ -298,7 +297,7 @@ class ConnectionInformation:
|
|||
|
||||
return new_info
|
||||
|
||||
def make_become_cmd(self, cmd, executable ):
|
||||
def make_become_cmd(self, cmd, executable='/bin/sh'):
|
||||
""" helper function to create privilege escalation commands """
|
||||
|
||||
prompt = None
|
||||
|
@ -356,19 +355,6 @@ class ConnectionInformation:
|
|||
|
||||
return (cmd, prompt, success_key)
|
||||
|
||||
def check_become_success(self, output, success_key):
|
||||
return success_key in output
|
||||
|
||||
def check_password_prompt(self, output, prompt):
|
||||
if isinstance(prompt, basestring):
|
||||
return output.endswith(prompt)
|
||||
else:
|
||||
return prompt(output)
|
||||
|
||||
def check_incorrect_password(self, output, prompt):
|
||||
incorrect_password = gettext.dgettext(self.become_method, "Sorry, try again.")
|
||||
return output.endswith(incorrect_password)
|
||||
|
||||
def _get_fields(self):
|
||||
return [i for i in self.__dict__.keys() if i[:1] != '_']
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ class ActionBase:
|
|||
debug("done with _execute_module (%s, %s)" % (module_name, module_args))
|
||||
return data
|
||||
|
||||
def _low_level_execute_command(self, cmd, tmp, executable=None, sudoable=True, in_data=None):
|
||||
def _low_level_execute_command(self, cmd, tmp, sudoable=True, in_data=None):
|
||||
'''
|
||||
This is the function which executes the low level shell command, which
|
||||
may be commands to create/remove directories for temporary files, or to
|
||||
|
@ -438,17 +438,15 @@ class ActionBase:
|
|||
debug("no command, exiting _low_level_execute_command()")
|
||||
return dict(stdout='', stderr='')
|
||||
|
||||
if executable is None:
|
||||
executable = C.DEFAULT_EXECUTABLE
|
||||
|
||||
prompt = None
|
||||
success_key = None
|
||||
|
||||
if sudoable:
|
||||
cmd, prompt, success_key = self._connection_info.make_become_cmd(cmd, executable)
|
||||
#FIXME: disabled as this should happen in the connection plugin, verify before removing
|
||||
#prompt = None
|
||||
#success_key = None
|
||||
#
|
||||
#if sudoable:
|
||||
# cmd, prompt, success_key = self._connection_info.make_become_cmd(cmd)
|
||||
|
||||
debug("executing the command %s through the connection" % cmd)
|
||||
rc, stdin, stdout, stderr = self._connection.exec_command(cmd, tmp, executable=executable, in_data=in_data)
|
||||
rc, stdin, stdout, stderr = self._connection.exec_command(cmd, tmp, in_data=in_data, sudoable=sudoable)
|
||||
debug("command execution done")
|
||||
|
||||
if not isinstance(stdout, basestring):
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import gettext
|
||||
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||
|
||||
from functools import wraps
|
||||
|
@ -97,7 +98,7 @@ class ConnectionBase(with_metaclass(ABCMeta, object)):
|
|||
|
||||
@ensure_connect
|
||||
@abstractmethod
|
||||
def exec_command(self, cmd, tmp_path, executable=None, in_data=None, sudoable=True):
|
||||
def exec_command(self, cmd, tmp_path, in_data=None, sudoable=True):
|
||||
"""Run a command on the remote host"""
|
||||
pass
|
||||
|
||||
|
@ -117,3 +118,17 @@ class ConnectionBase(with_metaclass(ABCMeta, object)):
|
|||
def close(self):
|
||||
"""Terminate the connection"""
|
||||
pass
|
||||
|
||||
def check_become_success(self, output, success_key):
|
||||
return success_key in output
|
||||
|
||||
def check_password_prompt(self, output, prompt):
|
||||
if isinstance(prompt, basestring):
|
||||
return output.endswith(prompt)
|
||||
else:
|
||||
return prompt(output)
|
||||
|
||||
def check_incorrect_password(self, output, prompt):
|
||||
incorrect_password = gettext.dgettext(self._connection_info.become_method, "Sorry, try again.")
|
||||
return output.endswith(incorrect_password)
|
||||
|
||||
|
|
|
@ -46,10 +46,10 @@ class Connection(ConnectionBase):
|
|||
self._connected = True
|
||||
return self
|
||||
|
||||
def exec_command(self, cmd, tmp_path, executable='/bin/sh', in_data=None):
|
||||
def exec_command(self, cmd, tmp_path, in_data=None):
|
||||
''' run a command on the local host '''
|
||||
|
||||
super(Connection, self).exec_command(cmd, tmp_path, executable=executable, in_data=in_data)
|
||||
super(Connection, self).exec_command(cmd, tmp_path, in_data=in_data)
|
||||
|
||||
debug("in local.exec_command()")
|
||||
# su requires to be run from a terminal, and therefore isn't supported here (yet?)
|
||||
|
@ -59,7 +59,7 @@ class Connection(ConnectionBase):
|
|||
if in_data:
|
||||
raise AnsibleError("Internal Error: this module does not support optimized module pipelining")
|
||||
|
||||
executable = executable.split()[0] if executable else None
|
||||
executable = self._connection_info.executable.split()[0] if self._connection_info.executable else None
|
||||
|
||||
self._display.vvv("{0} EXEC {1}".format(self._connection_info.remote_addr, cmd))
|
||||
# FIXME: cwd= needs to be set to the basedir of the playbook
|
||||
|
|
|
@ -174,10 +174,10 @@ class Connection(ConnectionBase):
|
|||
# fail early if the become password is wrong
|
||||
if self._connection_info.become and sudoable:
|
||||
if self._connection_info.become_pass:
|
||||
if self._connection_info.check_incorrect_password(stdout, prompt):
|
||||
if self.check_incorrect_password(stdout, prompt):
|
||||
raise AnsibleError('Incorrect %s password', self._connection_info.become_method)
|
||||
|
||||
elif self._connection_info.check_password_prompt(stdout, prompt):
|
||||
elif self.check_password_prompt(stdout, prompt):
|
||||
raise AnsibleError('Missing %s password', self._connection_info.become_method)
|
||||
|
||||
if p.stdout in rfd:
|
||||
|
@ -260,10 +260,10 @@ class Connection(ConnectionBase):
|
|||
self._display.vvv("EXEC previous known host file not found for {0}".format(host))
|
||||
return True
|
||||
|
||||
def exec_command(self, cmd, tmp_path, executable='/bin/sh', in_data=None, sudoable=True):
|
||||
def exec_command(self, cmd, tmp_path, in_data=None, sudoable=True):
|
||||
''' run a command on the remote host '''
|
||||
|
||||
super(Connection, self).exec_command(cmd, tmp_path, executable=executable, in_data=in_data, sudoable=sudoable)
|
||||
super(Connection, self).exec_command(cmd, tmp_path, in_data=in_data, sudoable=sudoable)
|
||||
|
||||
host = self._connection_info.remote_addr
|
||||
|
||||
|
@ -287,7 +287,7 @@ class Connection(ConnectionBase):
|
|||
prompt = None
|
||||
success_key = ''
|
||||
if sudoable:
|
||||
cmd, prompt, success_key = self._connection_info.make_become_cmd(cmd, executable)
|
||||
cmd, prompt, success_key = self._connection_info.make_become_cmd(cmd)
|
||||
|
||||
ssh_cmd.append(cmd)
|
||||
self._display.vvv("EXEC {0}".format(' '.join(ssh_cmd)), host=host)
|
||||
|
@ -323,8 +323,8 @@ class Connection(ConnectionBase):
|
|||
become_errput = ''
|
||||
|
||||
while True:
|
||||
if self._connection_info.check_become_success(become_output, success_key) or \
|
||||
self._connection_info.check_password_prompt(become_output, prompt ):
|
||||
if self.check_become_success(become_output, success_key) or \
|
||||
self.check_password_prompt(become_output, prompt ):
|
||||
break
|
||||
rfd, wfd, efd = select.select([p.stdout, p.stderr], [], [p.stdout], self._connection_info.timeout)
|
||||
if p.stderr in rfd:
|
||||
|
@ -333,7 +333,7 @@ class Connection(ConnectionBase):
|
|||
raise AnsibleError('ssh connection closed waiting for privilege escalation password prompt')
|
||||
become_errput += chunk
|
||||
|
||||
if self._connection_info.check_incorrect_password(become_errput, prompt):
|
||||
if self.check_incorrect_password(become_errput, prompt):
|
||||
raise AnsibleError('Incorrect %s password', self._connection_info.become_method)
|
||||
|
||||
if p.stdout in rfd:
|
||||
|
@ -347,7 +347,7 @@ class Connection(ConnectionBase):
|
|||
stdout = p.communicate()
|
||||
raise AnsibleError('ssh connection error waiting for sudo or su password prompt')
|
||||
|
||||
if not self._connection_info.check_become_success(become_output, success_key):
|
||||
if not self.check_become_success(become_output, success_key):
|
||||
if sudoable:
|
||||
stdin.write(self._connection_info.become_pass + '\n')
|
||||
else:
|
||||
|
|
Loading…
Reference in a new issue