Feature "ask_sudo_password" breaks interactivity of scripts
Version 2.0 RC1
I know that the CM is primarily meant to be used for unattended setups. But sometimes interaction is helpful too.
I came across the following issue while I was experimenting with executing commands using sudo or switching to the root user within my script completely. The latter is not possible without dropping to a interactive root shell so this unfortunately is not possible with welder. A workaround could be to execute su - -c 'whoami'
but using this command you have to enter the root password every time and every command in your script needs the su - -c ' ... '
prepended.
But let's start from the beginning:
In my setup.sh
I have a line which waits for a keypress before executing the script. The whole script looks like this:
#!/usr/bin/env bash
set -o nounset ## set -u : exit the script if you try to use an uninitialised variable
set -o errexit ## set -e : exit the script if any statement returns a non-true return value
# Setup colors
RED='\e[31m'
BLUE='\e[36m'
GREEN='\e[0;32m'
NC='\e[39m' # No Color
echo " "
echo " "
echo -e "${RED}Please CAREFULLY verify the target BEFORE you continue.${NC}"
echo " "
read -n 1 -s -r -p "Press ANY key to start the deployment to ${W_SSH_URL}..."
echo " "
# -------------------------------- #
sudo pwd
sudo whoami
echo " "
echo -e "${GREEN}DONE!${NC}"
echo " "
As soon as I set the parameter ask_sudo_password: true
the whole run procedure is running into a timeout waiting for the keypress but I did not get any output from welder:
welder run testserver
[ ?? ] Sudo password for user@192.168.0.5:
[ .. ] module 'test' Traceback (most recent call last):
File "/home/user/.local/bin/welder", line 33, in <module>
sys.exit(load_entry_point('welder==2.0rc1', 'console_scripts', 'welder')())
File "/home/user/.local/lib/python3.10/site-packages/welder/cli.py", line 125, in cli_entry
cli(auto_envvar_prefix='WELDER')
File "/usr/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
return self.main(*args, **kwargs)
File "/usr/lib/python3.10/site-packages/click/core.py", line 1055, in main
rv = self.invoke(ctx)
File "/usr/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/lib/python3.10/site-packages/click/core.py", line 760, in invoke
return __callback(*args, **kwargs)
File "/usr/lib/python3.10/site-packages/click/decorators.py", line 38, in new_func
return f(get_current_context().obj, *args, **kwargs)
File "/home/user/.local/lib/python3.10/site-packages/welder/cli.py", line 79, in run
RunCmd().run(workspace, config)
File "/home/user/.local/lib/python3.10/site-packages/welder/cmds/run_cmd.py", line 40, in run
server.execute_cmd(config.content, Path('setup.sh'))
File "/home/user/.local/lib/python3.10/site-packages/welder/remote_server.py", line 42, in execute_cmd
self.ssh.exec_script(launcher_script, True)
File "/home/user/.local/lib/python3.10/site-packages/welder/ssh_connection.py", line 29, in exec_script
index = child.expect(['\[sudo\] password for .*:', pexpect.EOF])
File "/usr/lib/python3.10/site-packages/pexpect/spawnbase.py", line 343, in expect
return self.expect_list(compiled_pattern_list,
File "/usr/lib/python3.10/site-packages/pexpect/spawnbase.py", line 372, in expect_list
return exp.expect_loop(timeout)
File "/usr/lib/python3.10/site-packages/pexpect/expect.py", line 181, in expect_loop
return self.timeout(e)
File "/usr/lib/python3.10/site-packages/pexpect/expect.py", line 144, in timeout
raise exc
pexpect.exceptions.TIMEOUT: Timeout exceeded.
<pexpect.pty_spawn.spawn object at 0x7f03823ab250>
command: /usr/bin/ssh
args: ['/usr/bin/ssh', '-qtp', '20917', 'user@192.168.0.5', '--', "#!/usr/bin/env bash\nset -o nounset\nset -o errexit\nexport W_SSH_PORT=20917\nexport W_SSH_URL=user@192.168.0.5\nexport W_ASK_SUDO_PASSWORD=1\nexport W_MODULES='(test)'\nexport W=.welder/files\n.welder/setup.sh"]
buffer (last 100 chars): b'et BEFORE you continue.\x1b[39m\r\n \r\nPress ANY key to start the deployment to user@192.168.0.5...'
before (last 100 chars): b'et BEFORE you continue.\x1b[39m\r\n \r\nPress ANY key to start the deployment to user@192.168.0.5...'
after: <class 'pexpect.exceptions.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 1279534
child_fd: 5
closed: False
timeout: 30
delimiter: <class 'pexpect.exceptions.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1
searcher: searcher_re:
0: re.compile(b'\\[sudo\\] password for .*:')
1: EOF
…
[WARN] Execution aborted!
I could identify the parameter ask_sudo_password: true
as the main cause because as soon as I comment it out everything works like expected:
$ welder run testserver
[ .. ] module 'test'
Please CAREFULLY verify the target BEFORE you continue.
Press ANY key to start the deployment to user@192.168.0.5...
[sudo] Passwort für user:
/home/user
root
DONE!
[ OK ] module 'test'
[ OK ] all done!
Maybe I got the whole sudo feature wrong but I would expect that setting ask_sudo_password: true
would not prevent the script from waiting for interactions from the user.