Repository: ansible/ansible

Issue:
Agnostic become password prompt not compatible w/ Tower
The new hardcoded `BECOME password` prompt introduced by https://github.com/ansible/ansible/pull/33789/files is a breaking change for stable Tower, which is unable to process jobs as it expects `SUDO password[defaults to SSH password]:` when using the sudo escalation method.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
ansible-playbook cli

##### ANSIBLE VERSION
```
ansible 2.5.0
```

##### CONFIGURATION
Ansible 2.5.0 running Tower 3.2.2 job w/ sudo escalation.

##### SUMMARY
The Tower job environment expects ansible to provide escalation method-specific password prompts (current awx expected prompts here: https://github.com/ansible/awx/blob/devel/awx/main/tasks.py#L1194).  By hardcoding to `BECOME`, all supported versions of tower are unable to run jobs.


Discussion:
I'm not sure how to handle that.  I suppose we could introduce a config that likely only tower would ever use, but the purpose of that change is to fix misleading behavior, so I'd be -1 on reverting/removing it.

Could tower be updated to handle the change?
Functionality could potentially be added to new versions moving forward (cc @matburt, @ghjm), but this is for all current Tower versions, so functionally a revert seems necessary.
cc @bcoca 
I like the idea of changing it to "BECOME password."  It makes more sense for the user, and hardcoding it like that is better for Tower in the long run as well, because it won't change based on future logic around the become method.

However, we can't change Tower versions that have already shipped and are being run by customers. So making the change in this way would mean existing Tower customers could not upgrade to Ansible 2.5, until/unless we do a new release for all supported minor versions of Tower. It would also mean baking Ansible-version-specific logic into Tower, because future Tower versions still have to preserve compatibility with older Ansible.

Is there any way we can think of to accomplish this change without breaking Tower?
I think what we've traditionally done is introduce an immediately deprecated config option.  So installs of old tower can toggle the config setting to be used with newer ansible at the expense of seeing a new deprecation warning.  New tower releases need to handle the version check (or expect BECOME as one of the valid prompts on any version).  Our current deprecation cycle is 4 releases (I think that equates to a year plus change).  I don't know whether we've allowed longer deprecation cycles for things that old releases of tower depend on but we discuss that if you think that will be an issue.
The problem is that any default change, even if there's a config setting, requires respinning old releases to work with it.
I'm just concerned that we take a step back in terms of behavior by reverting.  The change was added to address misleading behavior.

To describe that misleading behavior:

A user specifies `--ask-become-pass` on the CLI, but has hosts configured with `ansible_become_method: su` and `ansible_become: true` (or very similar).  The become pass, will still work for the user, however they are only concerned with `su`, but the playbook is not aware of this context, and it asks for a `SUDO` password.
@sivel I understand the issue and as I mentioned above, I agree with your solution to it, in isolation from other considerations.

However, the other considerations here are very serious. Is cleaning up some misleading language in the UI worth breaking Tower?

Perhaps there are other options besides just accepting or reverting this commit. Can Ansible figure out that what it really wants is a SU password, and ask for that? Tower will parse it fine in that case. Or perhaps there's some other creative solution.
We are having some discussions. I don't mean to sound adversarial (if I came off that way), I just want to make sure our solution isn't a step backwards.
Ok, sounds good. I look forward to seeing what you come up with. Thanks!
In the tower code (Does not address notting's concern about how to get this working with old tower) I think we can change the regex like this:

Currently:
``` python
        for method in PRIVILEGE_ESCALATION_METHODS:
            d[re.compile(r'%s password.*:\s*?$' % (method[0]), re.M)] = 'become_password'
            d[re.compile(r'%s password.*:\s*?$' % (method[0].upper()), re.M)] = 'become_password'
```
Fixed version:
``` python
        methods = '|'.join(m[0] for m in PRIVILEGE_ESCALATION_METHODS)
        d[re.compile(r'(BECOME|%s) password.*:\s*?$' % (methods), re.M|re.I)] = 'become_password'
```

(Although I'm not sure if there's some reason that this was done as separate regexes in the first place.  If so, then simply add a new regex for BECOME password instead of combining them all into a single regex).
I think we know how to make the changes to Tower/AWX code, it's just the act of going back to previous releases that has us concerned.
Any more news on this?  As @ghjm and @matburt mentioned, releasing this change in 2.5 _will_ prevent _all_ current and past awx/Tower users from upgrading to 2.5.
@sivel @abadger @bcoca see above

The Tower team really needs to know what's expected to be in 2.5, and I really want the answer to be "not this, yet."
We can't break install/backward compatibility like that.  But @ghjm @matburt @ryanpetrello is Toshio's "toggle" suggestion above a sufficient fix or not?
I'm happy for it to be a toggle, as long as the default in 2.5 is the old behavior.  If we make it the default in 2.6, that should be post-Tower 3.3, so that should be fine too.
I will be working on the implementation soon.  We are going to add a config and default the value to the old behavior (using the actual method in the message).  Per discussions, we will look to change that default to use agnostic BECOME messages, in either the 2.6 release or the 2.7 release, whichever happens after the Tower 3.3 release.
Sounds good to me @sivel - thanks!

Resolving patch:
diff --git a/lib/ansible/cli/__init__.py b/lib/ansible/cli/__init__.py
--- a/lib/ansible/cli/__init__.py
+++ b/lib/ansible/cli/__init__.py
@@ -320,14 +320,16 @@ def ask_passwords(self):
         becomepass = None
         become_prompt = ''
 
+        become_prompt_method = "BECOME" if C.AGNOSTIC_BECOME_PROMPT else op.become_method.upper()
+
         try:
             if op.ask_pass:
                 sshpass = getpass.getpass(prompt="SSH password: ")
-                become_prompt = "BECOME password[defaults to SSH password]: "
+                become_prompt = "%s password[defaults to SSH password]: " % become_prompt_method
                 if sshpass:
                     sshpass = to_bytes(sshpass, errors='strict', nonstring='simplerepr')
             else:
-                become_prompt = "BECOME password: "
+                become_prompt = "%s password: " % become_prompt_method
 
             if op.become_ask_pass:
                 becomepass = getpass.getpass(prompt=become_prompt)


Test patch: