Repository: ansible/ansible

Issue:
sudo=true in config confuses argument parsing
### Steps to reproduce

```
# touch play.yml
# ansible-playbook --ask-sudo-pass play.yml
Usage: ansible-playbook playbook.yml

ansible-playbook: error: Sudo arguments ('--sudo', '--sudo-user', and '--ask-sudo-pass') and su arguments ('-su', '--su-user', and '--ask-su-pass') and become arguments ('--become', '--become-user', and '--ask-become-pass') are exclusive of each other
```
### Potential cause

[This code](https://github.com/ansible/ansible/blob/8a0b8629e86efeddec7da5f8976231deee000f7f/v2/ansible/utils/cli.py#L268-L280) migrates `--ask-sudo-pass` to the new `become` options, _but does not remove the sudo setting_. Then [this code](https://github.com/ansible/ansible/blob/8a0b8629e86efeddec7da5f8976231deee000f7f/v2/ansible/utils/cli.py#L283-L301) fails because both settings are set. 
### Version

```
# ansible-playbook --version
ansible-playbook 1.9.0.1
  configured module search path = None
```



Discussion:
so I cannot reproduce the issue and the code you are looking at is in v2 which is not used in 1.9

checked v2 and the validation code runs before the normalization code, so this should not happen even when using the v2 binaries.

@bcoca sorry, didn't realize about the default branch not being 1.9.

[Here's the 1.9 normalization](https://github.com/ansible/ansible/blob/a00056723fe8798bf6b18607a26d73d1a306c610/lib/ansible/utils/__init__.py#L1157-L1169) and [and 1.9 checking](https://github.com/ansible/ansible/blob/a00056723fe8798bf6b18607a26d73d1a306c610/lib/ansible/utils/__init__.py#L1644-L1657) code.

Normalization happens on [line 132](https://github.com/ansible/ansible/blob/a00056723fe8798bf6b18607a26d73d1a306c610/bin/ansible-playbook#L132), and the mutually exclusive happens at [line 112](https://github.com/ansible/ansible/blob/a00056723fe8798bf6b18607a26d73d1a306c610/bin/ansible-playbook#L112), so the ordering looks right. I added some prints to those parts of my installed code, and can clearly see that the checking for exclusive happens _before_ the normalization. Now I just have to figure out why multiple values are being set.

@bcoca OK, I got this to reproduce in a fresh Ubuntu docker container. Turns out the issue is with having a config file. Sorry for the misleading initial report:

```
# cat conf
[defaults]
sudo = True

# touch foo.yml

# ANSIBLE_CONFIG=./conf ansible-playbook foo.yml
Usage: ansible-playbook playbook.yml

ansible-playbook: error: Sudo arguments ('--sudo', '--sudo-user', and '--ask-sudo-pass') and su arguments ('-su', '--su-user', and '--ask-su-pass') and become arguments ('--become', '--become-user', and '--ask-become-pass') are exclusive of each other
```

ok, this makes more sense, had missed this test case

Set become to default False and become_user to default empty. Because this default values prevent to use sudo or su


Resolving patch:
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
--- a/lib/ansible/constants.py
+++ b/lib/ansible/constants.py
@@ -112,7 +112,6 @@ def shell_expand_path(path):
 DEFAULT_REMOTE_USER       = get_config(p, DEFAULTS, 'remote_user',      'ANSIBLE_REMOTE_USER',      active_user)
 DEFAULT_ASK_PASS          = get_config(p, DEFAULTS, 'ask_pass',  'ANSIBLE_ASK_PASS',    False, boolean=True)
 DEFAULT_PRIVATE_KEY_FILE  = shell_expand_path(get_config(p, DEFAULTS, 'private_key_file', 'ANSIBLE_PRIVATE_KEY_FILE', None))
-DEFAULT_SUDO_USER         = get_config(p, DEFAULTS, 'sudo_user',        'ANSIBLE_SUDO_USER',        'root')
 DEFAULT_ASK_SUDO_PASS     = get_config(p, DEFAULTS, 'ask_sudo_pass',    'ANSIBLE_ASK_SUDO_PASS',    False, boolean=True)
 DEFAULT_REMOTE_PORT       = get_config(p, DEFAULTS, 'remote_port',      'ANSIBLE_REMOTE_PORT',      None, integer=True)
 DEFAULT_ASK_VAULT_PASS    = get_config(p, DEFAULTS, 'ask_vault_pass',    'ANSIBLE_ASK_VAULT_PASS',    False, boolean=True)
@@ -123,6 +122,7 @@ def shell_expand_path(path):
 DEFAULT_SYSLOG_FACILITY   = get_config(p, DEFAULTS, 'syslog_facility',  'ANSIBLE_SYSLOG_FACILITY', 'LOG_USER')
 DEFAULT_KEEP_REMOTE_FILES = get_config(p, DEFAULTS, 'keep_remote_files', 'ANSIBLE_KEEP_REMOTE_FILES', False, boolean=True)
 DEFAULT_SUDO              = get_config(p, DEFAULTS, 'sudo', 'ANSIBLE_SUDO', False, boolean=True)
+DEFAULT_SUDO_USER         = get_config(p, DEFAULTS, 'sudo_user',        'ANSIBLE_SUDO_USER',        'root')
 DEFAULT_SUDO_EXE          = get_config(p, DEFAULTS, 'sudo_exe', 'ANSIBLE_SUDO_EXE', 'sudo')
 DEFAULT_SUDO_FLAGS        = get_config(p, DEFAULTS, 'sudo_flags', 'ANSIBLE_SUDO_FLAGS', '-H')
 DEFAULT_HASH_BEHAVIOUR    = get_config(p, DEFAULTS, 'hash_behaviour', 'ANSIBLE_HASH_BEHAVIOUR', 'replace')
@@ -139,10 +139,10 @@ def shell_expand_path(path):
 #TODO: get rid of ternary chain mess
 BECOME_METHODS            = ['sudo','su','pbrun','pfexec','runas']
 BECOME_ERROR_STRINGS      = {'sudo': 'Sorry, try again.', 'su': 'Authentication failure', 'pbrun': '', 'pfexec': '', 'runas': ''}
-DEFAULT_BECOME            = get_config(p, 'privilege_escalation', 'become', 'ANSIBLE_BECOME',True if DEFAULT_SUDO or DEFAULT_SU else False, boolean=True)
+DEFAULT_BECOME            = get_config(p, 'privilege_escalation', 'become', 'ANSIBLE_BECOME',False, boolean=True)
 DEFAULT_BECOME_METHOD     = get_config(p, 'privilege_escalation', 'become_method', 'ANSIBLE_BECOME_METHOD','sudo' if DEFAULT_SUDO else 'su' if DEFAULT_SU else 'sudo' ).lower()
-DEFAULT_BECOME_USER       = get_config(p, 'privilege_escalation', 'become_user', 'ANSIBLE_BECOME_USER',DEFAULT_SUDO_USER if DEFAULT_SUDO else DEFAULT_SU_USER if DEFAULT_SU else 'root')
-DEFAULT_BECOME_ASK_PASS   = get_config(p, 'privilege_escalation', 'become_ask_pass', 'ANSIBLE_BECOME_ASK_PASS',True if DEFAULT_ASK_SUDO_PASS else False, boolean=True)
+DEFAULT_BECOME_USER       = get_config(p, 'privilege_escalation', 'become_user', 'ANSIBLE_BECOME_USER',default=None)
+DEFAULT_BECOME_ASK_PASS   = get_config(p, 'privilege_escalation', 'become_ask_pass', 'ANSIBLE_BECOME_ASK_PASS', False, boolean=True)
 # need to rethink impementing these 2
 DEFAULT_BECOME_EXE = None
 #DEFAULT_BECOME_EXE        = get_config(p, DEFAULTS, 'become_exe', 'ANSIBLE_BECOME_EXE','sudo' if DEFAULT_SUDO else 'su' if DEFAULT_SU else 'sudo')
diff --git a/v2/ansible/constants.py b/v2/ansible/constants.py
--- a/v2/ansible/constants.py
+++ b/v2/ansible/constants.py
@@ -145,10 +145,10 @@ def shell_expand_path(path):
 #TODO: get rid of ternary chain mess
 BECOME_METHODS            = ['sudo','su','pbrun','pfexec','runas']
 BECOME_ERROR_STRINGS      = {'sudo': 'Sorry, try again.', 'su': 'Authentication failure', 'pbrun': '', 'pfexec': '', 'runas': ''}
-DEFAULT_BECOME            = get_config(p, 'privilege_escalation', 'become', 'ANSIBLE_BECOME',True if DEFAULT_SUDO or DEFAULT_SU else False, boolean=True)
+DEFAULT_BECOME            = get_config(p, 'privilege_escalation', 'become', 'ANSIBLE_BECOME',False, boolean=True)
 DEFAULT_BECOME_METHOD     = get_config(p, 'privilege_escalation', 'become_method', 'ANSIBLE_BECOME_METHOD','sudo' if DEFAULT_SUDO else 'su' if DEFAULT_SU else 'sudo' ).lower()
-DEFAULT_BECOME_USER       = get_config(p, 'privilege_escalation', 'become_user', 'ANSIBLE_BECOME_USER',DEFAULT_SUDO_USER if DEFAULT_SUDO else DEFAULT_SU_USER if DEFAULT_SU else 'root')
-DEFAULT_BECOME_ASK_PASS   = get_config(p, 'privilege_escalation', 'become_ask_pass', 'ANSIBLE_BECOME_ASK_PASS',True if DEFAULT_ASK_SUDO_PASS else False, boolean=True)
+DEFAULT_BECOME_USER       = get_config(p, 'privilege_escalation', 'become_user', 'ANSIBLE_BECOME_USER', None)
+DEFAULT_BECOME_ASK_PASS   = get_config(p, 'privilege_escalation', 'become_ask_pass', 'ANSIBLE_BECOME_ASK_PASS', False, boolean=True)
 # need to rethink impementing these 2
 DEFAULT_BECOME_EXE = None
 #DEFAULT_BECOME_EXE        = get_config(p, DEFAULTS, 'become_exe', 'ANSIBLE_BECOME_EXE','sudo' if DEFAULT_SUDO else 'su' if DEFAULT_SU else 'sudo')


Test patch: