pyinfra-dev / pyinfra

pyinfra turns Python code into shell commands and runs them on your servers. Execute ad-hoc commands and write declarative operations. Target SSH servers, local machine and Docker containers. Fast and scales from one server to thousands.
https://pyinfra.com
MIT License
3.91k stars 383 forks source link

USE_SUDO_PASSWORD works only if it is a hardcode string #676

Closed oz123 closed 3 years ago

oz123 commented 3 years ago

Describe the bug

I have a script with the following:

from pyinfra.operations import server

SUDO = True

x = lambda: 'mysecretsudopassword'
# USE_SUDO_PASSWORD = 'mysecretsudopassword'
USE_SUDO_PASSWORD = x()
import pdb; pdb.set_trace()
nfs_mounts = [
...
]

for line in nfs_mounts:
    server.files.line(
        '/etc/fstab', line, present=True, backup=True,
    )

Using USE_SUDO_PASSWORD = 'mysecretsudopassword' with:

 pyinfra  --user oz123 --password  mysecretsudopassword server nfs-mounts.py

works as expected. I am not asked for sudo password.

However, if USE_SUDO_PASSWORD is assigned a value of a called function, e.g. as with the lambda, it fails with:

--> Preparing operations...
    Loading: nfs-mounts.py
    [server] sudo: a password is required
    [server] Error: could not load fact: find_in_file path=/etc/fstab, pattern=^.*content*$
--> An unexpected exception occurred in: nfs-mounts.py:

To Reproduce

Call pyinfra with my similar example.

Expected behavior

I would expect this to work, since it opens the way to reading secret from the environment or on the fly decryption of files.

Because config.py is loaded and parsed with ast.parser I don't see an obvious way of doing this. Given more time, I might be able to submit a patch. On the other hand, I know you are already working on a patch related to this issue..

Meta

Fizzadar commented 3 years ago

Hi @oz123 - this is an unfortunate consequence of using AST to parse the config files. The upcoming v1.5 adds a pyinfra.config object that can recieve any type of value and does not go through the AST like this.

You may also set USE_SUDO_PASSWORD=True to have pyinfra prompt for the password at runtime, although this is not helpful to integrate with some external system.

I'm going to ensure this use-case works in v1.5.

oz123 commented 3 years ago

Yes, using True does work and prompt. The problem is that if I have 10s of system, I have to manually write the password for each host, or simply wrap pyinfra with something that writes config.py. Aren't we wall are system admins :'-) who constantly wrap software with more shell glue around?

Fizzadar commented 3 years ago

v1.5 is now out so this should be possible via:

from pyinfra import config

config.USE_SUDO_PASSWORD = ...