-
Notifications
You must be signed in to change notification settings - Fork 384
Closed
Description
tl;dr Fabric 1's sudo() except implemented on top of generic, user-exposed features (#289, #293) and available at Invoke-on-up, since it's not actually specific to remote execution.
Given those user-exposed features, there's no technical necessity to implement it in core, because it should just turn into something like this:
@task
def identity(c):
assert c.run("whoami").stdout.strip() == "myuser"
sudo_prompt = "Sudo password plz:"
with c.prefix("sudo -S -p '{0}' ".format(sudo_prompt):
result = c.run("whoami", responses={sudo_prompt: "mysudopassword\n"})
assert result.stdout.strip() == "root"But clearly, even if you remove the asserts, that's annoying boilerplate we can erase by implementing a commonly used pattern as a convenience method.
MUCH LATER EDIT: There is a wrinkle here - in Fabric 1, this functionality includes "prompt the user ourselves when the sudo-prompt response value isn't pre-set, then cache the result from then on". That prompt+cache happens "inline" within the sudo() call. Brainstorm:
- The most-obvious answer is "you should store it in your config up front so no prompting is necessary".
- But storing that data on-disk is insecure; a runtime prompt is better.
- A runtime "pulled from a secure store over the network, flash key, etc" is best. No prompt, no on-disk.
- But there's nothing saying we can't explicitly prompt up-front in
sudo. - Prompting "lazily" / as late as possible, is "nice" insofar as it means users with passwordless sudo never have to deal with a prompt at all - no inner prompt seen, no outer prompt displayed.
- In most cases, that is still just "nice" and not required - users who know up front that they will need the password, can simply enter it up front.
- But the Fabric-specific use case of remote sudo is more complex - users with large fleets may not know whether the prompt will ever appear.
- Counterpoint: users with large fleets will usually want "raise/store an exception and keep trucking" instead...
- Users may also have heterogenous sudo passwords across their fleets, so a single up-front prompt is no longer enough - it'd need to be one prompt per host/group/whatever.
- Counterpoint, if you have that setup, you could be using Fabric 2's per-host/group configs
- But then you're back to storing the data on-disk
- So you really do need one prompt per remote password, no matter when it pops up.
- If you know ahead of time where the passwords differ, we could then say "ok, you just need to prompt for each group" (perhaps with a config setting like e.g.
{'hostname': {'prompt_for_password': True}}) - If you don't, that is when runtime inline prompting becomes truly "necessary". Whether that's enough of a use case to be worth implementing this ourselves, hard to say.
- NOTE that all of these concerns pop up with Fabric connection/login passwords too - with the exception that the point of prompting is at connection time and not anywhere in
Runner.
- One way to enable "late but not inline" prompting is to have the prompt machinery raise an exception when it encounters a prompt key whose value is
None, thensudo()can treat this as "prompt, fill config, try that same command again"- This isn't exactly the same as Fabric 1's behavior, because it involves running the command literally twice in a row.
- But it feels cleaner because it doesn't require the truly-inline prompting.
- It also arguably lets us push the entirety of "dealing with missing password caches" on the user, which is better for 'training' them to do the right thing, but worse from a usability standpoint.
- If we did go with fully inline prompting again, at least we can make it more generic - again, anything whose value is
Nonecould trigger the pause-and-prompt, not just sudo specific passwords.- Though there's the added wrinkle of "when to use
getpass.getpassvs(raw_)input"...
- Though there's the added wrinkle of "when to use
- Yet another reason not to do inline prompting is that it adds implementation complexity - e.g. in Fabric 1 we need the prompt machinery to talk to the stdin handler so the stdin handler pauses itself while prompting is happening (otherwise
getpassorraw_inputnever see the stdin, as it's being intercepted).