Repository: ansible/ansible

Issue:
_remote_md5 fails when passing -K but no sudo password is required. 
##### Issue Type:

Bug Report
##### Ansible Version:

ansible 1.7 (devel b9a5242f03) last updated 2014/08/04 09:22:22 (GMT +1000)
##### Environment:

N/A
##### Summary:

When running e.g. the unarchive module in an ansible-playbook in sudo mode against a server and passing -K (ask sudo password) to a server that doesn't require a password to sudo, it fails with the message `dest '/target/directory'  must be an existing dir`. 

The source of this message the unarchive action_plugin, and that plugin believes that the directory does not exist because the `runner._remote_md5` call returns `INVALIDMD5SUM`. 

It would be good to get the error message improved. 
##### Steps To Reproduce:

Have a server with sudo (-u user) -i not require a password. 
Use unarchive to unarchive against the target server as the sudo user

```
  hosts: target

  tasks:
  - get_url: url="https://github.com/ansible/ansible-examples/archive/master.zip" dest=/var/tmp/ansible-examples.zip

  - unarchive: src="/var/tmp/ansible-examples.zip" dest="/var/tmp/" copy=no
```

Then run that playbook with the -K option and enter a password. 
##### Expected Results:

A message along the lines of 'You sent a password to a system that didn't ask for one'
Or ignoring the password if it is not required. 
##### Actual Results:

Failure with the message `dest '/target/directory' must be an existing dir`



Discussion:
We can see about improving the error message if it's possible to detect the result here.

Just hit this myself today. @willthames, thanks for describing the work-around until this is fixed.

Ansible will already not attempt passing the sudo password if provided and not prompted for.  This is what the SUDO-SUCCESS- echo statement is used for.

Are you saying this behaviour has changed since this issue was raised?

Will
On 05/09/2014 10:17 pm, "Matt Martz" notifications@github.com wrote:

> Ansible will already not attempt passing the sudo password if provided and
> not prompted for. This is what the SUDO-SUCCESS- echo statement is used for.
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/ansible/ansible/issues/8418#issuecomment-54617661.

No, I am saying that the functionality to not send the password, even if provided, was added in ansible 1.3 iirc.  So either something is partially broken currently, or something else is going on here.  I am taking a look currently.

A simple test of something like the following works without issue.  So it may be specifically related to md5 sums.  Not sure yet.

```
ansible all -i host.withpasswordlesssudo.com, --sudo -K -a whoami
```

It's entirely relayed to md5 sums, hence the title. Something about the
return code of the long md5 command that causes it to return 3. Thanks for
looking into this a bit harder though, I'd forgotten about it to be honest.

Will
On 05/09/2014 10:30 pm, "Matt Martz" notifications@github.com wrote:

> No, I am saying that the functionality to not send the password, even if
> provided, was added in ansible 1.3 iirc. So either something is partially
> broken currently, or something else is going on here. I am taking a look
> currently.
> 
> A simple test of something like the following works without issue. So it
> may be specifically related to md5 sums. Not sure yet.
> 
> ansible all -i host.withpasswordlesssudo.com, --sudo -K -a whoami
> 
> —
> Reply to this email directly or view it on GitHub
> https://github.com/ansible/ansible/issues/8418#issuecomment-54618689.


Resolving patch:
diff --git a/lib/ansible/runner/connection_plugins/paramiko_ssh.py b/lib/ansible/runner/connection_plugins/paramiko_ssh.py
--- a/lib/ansible/runner/connection_plugins/paramiko_ssh.py
+++ b/lib/ansible/runner/connection_plugins/paramiko_ssh.py
@@ -204,6 +204,8 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
                 msg += ": %s" % str(e)
             raise errors.AnsibleConnectionFailed(msg)
 
+        no_prompt_out = ''
+        no_prompt_err = ''
         if not (self.runner.sudo and sudoable) and not (self.runner.su and su):
 
             if executable:
@@ -259,6 +261,9 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
                             chan.sendall(self.runner.sudo_pass + '\n')
                         elif su:
                             chan.sendall(self.runner.su_pass + '\n')
+                    else:
+                        no_prompt_out += sudo_output
+                        no_prompt_err += sudo_output
 
             except socket.timeout:
 
@@ -267,7 +272,7 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
         stdout = ''.join(chan.makefile('rb', bufsize))
         stderr = ''.join(chan.makefile_stderr('rb', bufsize))
 
-        return (chan.recv_exit_status(), '', stdout, stderr)
+        return (chan.recv_exit_status(), '', no_prompt_out + stdout, no_prompt_out + stderr)
 
     def put_file(self, in_path, out_path):
         ''' transfer a file from local to remote '''
diff --git a/lib/ansible/runner/connection_plugins/ssh.py b/lib/ansible/runner/connection_plugins/ssh.py
--- a/lib/ansible/runner/connection_plugins/ssh.py
+++ b/lib/ansible/runner/connection_plugins/ssh.py
@@ -301,6 +301,8 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
 
         self._send_password()
 
+        no_prompt_out = ''
+        no_prompt_err = ''
         if (self.runner.sudo and sudoable and self.runner.sudo_pass) or \
                 (self.runner.su and su and self.runner.su_pass):
             # several cases are handled for sudo privileges with password
@@ -351,6 +353,9 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
                     stdin.write(self.runner.sudo_pass + '\n')
                 elif su:
                     stdin.write(self.runner.su_pass + '\n')
+            else:
+                no_prompt_out += sudo_output
+                no_prompt_err += sudo_errput
 
         (returncode, stdout, stderr) = self._communicate(p, stdin, in_data, su=su, sudoable=sudoable, prompt=prompt)
 
@@ -371,7 +376,7 @@ def exec_command(self, cmd, tmp_path, sudo_user=None, sudoable=False, executable
         if p.returncode == 255 and (in_data or self.runner.module_name == 'raw'):
             raise errors.AnsibleError('SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh')
 
-        return (p.returncode, '', stdout, stderr)
+        return (p.returncode, '', no_prompt_out + stdout, no_prompt_err + stderr)
 
     def put_file(self, in_path, out_path):
         ''' transfer a file from local to remote '''


Test patch: