When running on lots of hosts with a large login banner on a slow network, it was still possible that the first recv() didn't to pull in the sudo password prompt, and sudo would fail intermittently. This patch tells sudo to use a specific, randomly-generated prompt and then reads until it finds that prompt (or times out). Only then is the password sent. It also catches `socket.timeout` and thunks it to a more useful `AnsbileError` with the output of sudo so if something goes wrong you can see what's up.
This adds selinux_mls_enabled() and selinux_enabled() to detect a)
whether selinux is MLS aware (ie supports selevel) and b) whether
selinux is enabled. If selinux is not enabled, all selinux operations
are punted on -- same as if python's selinux module were not available.
In set_context_if_different(), I now iterate over the current context
instead of the context argument. Even if the system supports MLS, it
may not return the selevel from selinux.lgetfilecon(). Lastly, this
drops selinux_has_selevel() in lieu of the current approach.
Commit SHA: 87b1cf45 that put temp files in `$HOME/.ansible` instead of `/home/<user>/.ansible` was producing a directory literally called `$HOME` (no expansion) with non-sudo remote execution. I'll take the blame for this one, as `ParamikoConnection.exec_command()` was not using the shell for non-sudo commands. This does sudo and non-sudo execution the same way, using the shell, so environment variables should get expanded.
Older versions of selinux, such as that deployed on rhel5, only return a
context of user:role:type instead of user:role:type:level. This detects
whether the tuple has three elements (old-style) or four. If the
old-style, it keeps the secontext list at three elements.
Reading the docs, I was a bit confused as to how to specify multiple hosts/groups in a playbook. Being YAML, I assumed a normal YAML list would work:
---
- hosts: [host1, host2]
But this crashes when inventory._matches() assumes hosts is a string. This patch just checks if hosts is a list, and turns it into a string joined by ';'.
runner._return_from_module() normally returns a list (?) of `[str,bool,dict,str]`, but on error it returns `[str,bool,str,str]`. runner._chain_file_module() then tries to call .get() on the third item (`data2`), which fails when it's a string. This patch only accesses `data2` if the return value was `ok`. It might be better to return consistent types in both cases, but I'm not sure where/how else the return value is used.