Sudo fails to ask for a password if locale of remote system is not English
Describe the bug
If remote system is configured with a locale different than English, sudo will fail to prompt for a password.
On remote system:
echo $LANG
fr_FR.UTF-8
Example of failing command:
pyinfra --debug-all -y 192.168.1.16 server.shell "echo foo" _sudo=true
--> Starting operation: server.shell (echo foo)
[pyinfra.api.operations] Starting operation {'server.shell'} on 192.168.1.16
[pyinfra.connectors.ssh] Running command on 192.168.1.16: (pty=False) sudo -H -n sh -c 'echo foo'
DEBUG:paramiko.transport:[chan 0] Max packet in: 32768 bytes
DEBUG:paramiko.transport:[chan 0] Max packet out: 32768 bytes
DEBUG:paramiko.transport:Secsh channel 0 opened.
DEBUG:paramiko.transport:[chan 0] Sesch channel 0 request ok
DEBUG:paramiko.transport:[chan 0] EOF received (0)
DEBUG:paramiko.transport:[chan 0] EOF sent (0)
[pyinfra.connectors.ssh] Waiting for exit status...
[pyinfra.connectors.ssh] Command exit status: 1
[192.168.1.16] sudo: il est nécessaire de saisir un mot de passe
[192.168.1.16] Error: executed 0 commands
[pyinfra.api.state] Failing hosts: 192.168.1.16
The problem comes from this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L203
In this case, the remote system being in French, sudo prints sudo: il est nécessaire de saisir un mot de passe.
I "fixed" the bug by changing this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346
into
command_bits.extend(["LANG=C", "sudo", "-H"])
but I'm not sure whether this is the right fix.
Meta
Observed with Pip package 3.0b2.
I just spent this week-end testing Pyinfra, it looks promising! :+1:
Can confirm that this is caused by pyinfra using string matching on the sudo output, which depends on the locale. Unfortunately, there's no option to set that string (the --prompt option only applies to interactive runs), and the exit code in this situation is 1.
Setting LANG=C is a good workaround. You should be able to pass it via the _env argument that all operations accept. You should be able to specify it once in the inventory data too.
You should be able to pass it via the
_envargument that all operations accept. You should be able to specify it once in the inventory data too.
No, because using _env puts the environment variables inside the sudo command (ie sudo LANG=C echo foo), while we need to set the environment variable for sudo (ie LANG=C sudo echo foo).
Nice catch, definitely want to fix this! My worry with applying env everywhere is accidentally leaking into the sub command which may have unintended consequences..
I also ran into this issue.
I "fixed" the bug by changing this line:
https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346
into
command_bits.extend(["LANG=C", "sudo", "-H"])but I'm not sure whether this is the right fix.
This worked for me as well (de_DE.UTF-8).
My worry is that setting this might leak into the actual command:
sudo bash -c 'echo $LANG'
# => de_DE.UTF-8
LANG=C sudo bash -c 'echo $LANG'
# => C
This might break things if users of pyinfra match on the command output and the locale suddenly changes. Or am I getting things wrong? Environment variables should only be preserved when using -E, right?
I also ran into this issue.
I "fixed" the bug by changing this line: https://github.com/pyinfra-dev/pyinfra/blob/21b022b8eb0c9da2846867d3d6706d78163599c4/pyinfra/connectors/util.py#L346
into
command_bits.extend(["LANG=C", "sudo", "-H"])but I'm not sure whether this is the right fix.
This worked for me as well (
de_DE.UTF-8).My worry is that setting this might leak into the actual command:
sudo bash -c 'echo $LANG' # => de_DE.UTF-8 LANG=C sudo bash -c 'echo $LANG' # => CThis might break things if users of pyinfra match on the command output and the locale suddenly changes. Or am I getting things wrong? Environment variables should only be preserved when using
-E, right?
This fix worked for me too. Also de_DE.UTF-8.