Nested operations do not support programmatic sudo
Describe the bug
Trying to use nested operations which require programmatic sudo access throws AttributeError
UPDATE: perhaps this should just be that nested operations do not support custom config attributes(?)
To Reproduce
from pyinfra import config
config.USE_REMOTE_SUDO_PASSWORD = "something"
def callback():
result = server.shell(
commands=["cat foo"],
_sudo=True,
_use_sudo_password=config.USE_REMOTE_SUDO_PASSWORD
)
def caller(vm_name):
python.call(
name="Execute callback function",
function=callback,
)
[server.foo] Unexpected error in Python callback: AttributeError("'Config' object has no attribute 'USE_REMOTE_SUDO_PASSWORD'",)
Expected behavior
I would expect a nested operation to support programmtic sudo access
Meta
- Include output of
pyinfra --support.
System: Linux
Platform: Linux-5.10.105-1-MANJARO-x86_64-with-glibc2.35
Release: 5.10.105-1-MANJARO
Machine: x86_64
pyinfra: v2.1
Executable: /home/user/workspace/something/venv/bin/pyinfra
Python: 3.10.4 (CPython, GCC 11.2.0)
The config variable here should be USE_SUDO_PASSWORD, that should work as expected!
OK, so I think what I used to do was create a global variable in the config object call USE_REMOTE_PASSWORD and that I passed to use_sudo_password. Now what I'm doing is just setting config.USE_SUDO_PASSWORD and config.SUDO at the top of the code and everything now works apart from the nested operation which just seems to ignore the config settings and not embed the shell snippet within the usual env SUDO_ASKPASS=pyinfra-sudo-askpass *** sh -c '<shell snippet'> like I would expect.
Very slow getting back on this, apologies. So the reason this fails is because the config object is unique per host and also per stage (first fact gathering then execution) - but the config for one host is not shared between each stage. This the function call here uses the original config without the extra attribute:
https://github.com/Fizzadar/pyinfra/blob/fa23aba0ac8742c246bbfacfb889caab1c796a98/pyinfra/api/command.py#L202
Quick workaround would be adding the attribute in config.py (or whatever --config X.py filename). Long term I think the original example you provide should work as expected, so config may need to be scoped by host rather than state to achieve that.