From 1c185b68bedfeb2e4339aadd20b623a24536d6cc Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Wed, 24 Jun 2015 12:12:54 -0400 Subject: [PATCH] Rearranging some become stuff in relation to action/connection plugins Moving the make_sudo_cmd() calls back up to the action level so that connection plugins don't have to know about it at all, and moving some of the become data (prompt and success_key) into the ConnectionInformation object so they don't need to be passed around needlessly. --- lib/ansible/executor/connection_info.py | 16 ++++++++++++---- lib/ansible/plugins/action/__init__.py | 4 ++++ lib/ansible/plugins/connections/__init__.py | 12 ++++++------ lib/ansible/plugins/connections/local.py | 5 +---- lib/ansible/plugins/connections/paramiko_ssh.py | 2 +- lib/ansible/plugins/connections/ssh.py | 6 +----- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/lib/ansible/executor/connection_info.py b/lib/ansible/executor/connection_info.py index a760cc9aabb..576ae745515 100644 --- a/lib/ansible/executor/connection_info.py +++ b/lib/ansible/executor/connection_info.py @@ -161,6 +161,8 @@ class ConnectionInformation: self.become_pass = passwords.get('become_pass','') self.become_exe = None self.become_flags = None + self.prompt = None + self.success_key = None # backwards compat self.sudo_exe = None @@ -317,18 +319,22 @@ class ConnectionInformation: return new_info - def make_become_cmd(self, cmd, executable=C.DEFAULT_EXECUTABLE): + def make_become_cmd(self, cmd, executable=None): """ helper function to create privilege escalation commands """ prompt = None success_key = None + print("in make_become_cmd, executable is: %s" % executable) + if executable is None: + executable = C.DEFAULT_EXECUTABLE + if self.become: becomecmd = None randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32)) success_key = 'BECOME-SUCCESS-%s' % randbits - executable = executable or '$SHELL' + #executable = executable or '$SHELL' success_cmd = pipes.quote('echo %s; %s' % (success_key, cmd)) if self.become_method == 'sudo': @@ -371,9 +377,11 @@ class ConnectionInformation: else: raise AnsibleError("Privilege escalation method not found: %s" % self.become_method) - return (('%s -c ' % executable) + pipes.quote(becomecmd), prompt, success_key) + self.prompt = prompt + self.success_key = success_key + return ('%s -c ' % executable) + pipes.quote(becomecmd) - return (cmd, prompt, success_key) + return ('%s -c ' % executable) + pipes.quote(cmd) def _get_fields(self): return [i for i in self.__dict__.keys() if i[:1] != '_'] diff --git a/lib/ansible/plugins/action/__init__.py b/lib/ansible/plugins/action/__init__.py index 5ef52a44f01..a97328b832b 100644 --- a/lib/ansible/plugins/action/__init__.py +++ b/lib/ansible/plugins/action/__init__.py @@ -429,6 +429,10 @@ class ActionBase: debug("no command, exiting _low_level_execute_command()") return dict(stdout='', stderr='') + print("in _low_level_execute_command, executable is: %s" % executable) + if sudoable: + cmd = self._connection_info.make_become_cmd(cmd, executable=executable) + debug("executing the command %s through the connection" % cmd) rc, stdin, stdout, stderr = self._connection.exec_command(cmd, tmp, in_data=in_data, sudoable=sudoable) debug("command execution done") diff --git a/lib/ansible/plugins/connections/__init__.py b/lib/ansible/plugins/connections/__init__.py index 449c9b9e696..1a74837e94d 100644 --- a/lib/ansible/plugins/connections/__init__.py +++ b/lib/ansible/plugins/connections/__init__.py @@ -118,7 +118,7 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): @ensure_connect @abstractmethod - def exec_command(self, cmd, tmp_path, in_data=None, sudoable=True): + def exec_command(self, cmd, tmp_path, in_data=None, executable=None, sudoable=True): """Run a command on the remote host""" pass @@ -140,15 +140,15 @@ class ConnectionBase(with_metaclass(ABCMeta, object)): pass def check_become_success(self, output): - return self.success_key in output + return self._connection_info.success_key in output def check_password_prompt(self, output): - if self.prompt is None: + if self._connection_info.prompt is None: return False - elif isinstance(self.prompt, basestring): - return output.endswith(self.prompt) + elif isinstance(self._connection_info.prompt, basestring): + return output.endswith(self._connection_info.prompt) else: - return self.prompt(output) + return self._connection_info.prompt(output) def check_incorrect_password(self, output): incorrect_password = gettext.dgettext(self._connection_info.become_method, C.BECOME_ERROR_STRINGS[self._connection_info.become_method]) diff --git a/lib/ansible/plugins/connections/local.py b/lib/ansible/plugins/connections/local.py index e046dc6c393..0c39e69866a 100644 --- a/lib/ansible/plugins/connections/local.py +++ b/lib/ansible/plugins/connections/local.py @@ -59,9 +59,6 @@ class Connection(ConnectionBase): raise AnsibleError("Internal Error: this module does not support optimized module pipelining") executable = C.DEFAULT_EXECUTABLE.split()[0] if C.DEFAULT_EXECUTABLE else None - if sudoable: - cmd, self.prompt, self.success_key = self._connection_info.make_become_cmd(cmd) - 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 debug("opening command with Popen()") @@ -75,7 +72,7 @@ class Connection(ConnectionBase): ) debug("done running command with Popen()") - if self.prompt and self._connection_info.become_pass: + if self._connection_info.prompt and self._connection_info.become_pass: fcntl.fcntl(p.stdout, fcntl.F_SETFL, fcntl.fcntl(p.stdout, fcntl.F_GETFL) | os.O_NONBLOCK) fcntl.fcntl(p.stderr, fcntl.F_SETFL, fcntl.fcntl(p.stderr, fcntl.F_GETFL) | os.O_NONBLOCK) become_output = '' diff --git a/lib/ansible/plugins/connections/paramiko_ssh.py b/lib/ansible/plugins/connections/paramiko_ssh.py index c8bc3e2553f..66a0b693445 100644 --- a/lib/ansible/plugins/connections/paramiko_ssh.py +++ b/lib/ansible/plugins/connections/paramiko_ssh.py @@ -223,7 +223,7 @@ class Connection(ConnectionBase): try: chan.exec_command(cmd) - if self.prompt: + if self._connection_info.prompt: while True: debug('Waiting for Privilege Escalation input') if self.check_become_success(become_output) or self.check_password_prompt(become_output): diff --git a/lib/ansible/plugins/connections/ssh.py b/lib/ansible/plugins/connections/ssh.py index f0c2db6bf99..66a13743de9 100644 --- a/lib/ansible/plugins/connections/ssh.py +++ b/lib/ansible/plugins/connections/ssh.py @@ -345,13 +345,9 @@ class Connection(ConnectionBase): ssh_cmd += ['-6'] ssh_cmd.append(self.host) - if sudoable: - cmd, self.prompt, self.success_key = self._connection_info.make_become_cmd(cmd) - ssh_cmd.append(cmd) self._display.vvv("EXEC {0}".format(' '.join(ssh_cmd)), host=self.host) - self.lock_host_keys(True) # create process @@ -362,7 +358,7 @@ class Connection(ConnectionBase): no_prompt_out = '' no_prompt_err = '' - if self.prompt: + if self._connection_info.prompt: ''' Several cases are handled for privileges with password * NOPASSWD (tty & no-tty): detect success_key on stdout