Navigation

Fabric’s primary operations, run and
sudo, are capable of sending local input to the remote
end, in a manner nearly identical to the ssh program. For example, programs
which display password prompts (e.g. a database dump utility, or changing a
user’s password) will behave just as if you were interacting with them
directly.

However, as with ssh itself, Fabric’s implementation of this feature is
subject to a handful of limitations which are not always intuitive. This
document discusses such issues in detail.

Note

Readers unfamiliar with the basics of Unix stdout and stderr pipes, and/or
terminal devices, may wish to visit the Wikipedia pages for Unix pipelines and Pseudo terminals respectively.

Fabric 0.9.x and earlier, and Python itself, buffer output on a line-by-line
basis: text is not printed to the user until a newline character is found.
This works fine in most situations but becomes problematic when one needs to
deal with partial-line output such as prompts.

Note

Line-buffered output can make programs appear to halt or freeze for no
reason, as prompts print out text without a newline, waiting for the user
to enter their input and press Return.

Newer Fabric versions buffer both input and output on a character-by-character
basis in order to make interaction with prompts possible. This has the
convenient side effect of enabling interaction with complex programs utilizing
the “curses” libraries or which otherwise redraw the screen (think top).

Unfortunately, printing to stderr and stdout simultaneously (as many programs
do) means that when the two streams are printed independently one byte at a
time, they can become garbled or meshed together. While this can sometimes be
mitigated by line-buffering one of the streams and not the other, it’s still a
serious issue.

To solve this problem, Fabric uses a setting in our SSH layer which merges the
two streams at a low level and causes output to appear more naturally. This
setting is represented in Fabric as the combine_stderr env var and
keyword argument, and is True by default.

Due to this default setting, output will appear correctly, but at the
cost of an empty .stderr attribute on the return values of
run/sudo, as all output will appear
to be stdout.

Conversely, users requiring a distinct stderr stream at the Python level and
who aren’t bothered by garbled user-facing output (or who are hiding stdout and
stderr from the command in question) may opt to set this to False as
needed.

Typical terminal applications or bona fide text terminals (e.g. when using a
Unix system without a running GUI) present programs with a terminal device
called a tty or pty (for pseudo-terminal). These automatically echo all text
typed into them back out to the user (via stdout), as interaction without
seeing what you had just typed would be difficult. Terminal devices are also
able to conditionally turn off echoing, allowing secure password prompts.

However, it’s possible for programs to be run without a tty or pty present at
all (consider cron jobs, for example) and in this situation, any stdin data
being fed to the program won’t be echoed. This is desirable for programs being
run without any humans around, and it’s also Fabric’s old default mode of
operation.

Unfortunately, in the context of executing commands via Fabric, when no pty is
present to echo a user’s stdin, Fabric must echo it for them. This is
sufficient for many applications, but it presents problems for password
prompts, which become insecure.

In the interests of security and meeting the principle of least surprise
(insofar as users are typically expecting things to behave as they would when
run in a terminal emulator), Fabric 1.0 and greater force a pty by default.
With a pty enabled, Fabric simply allows the remote end to handle echoing or
hiding of stdin and does not echo anything itself.

Note

In addition to allowing normal echo behavior, a pty also means programs
that behave differently when attached to a terminal device will then do so.
For example, programs that colorize output on terminals but not when run in
the background will print colored output. Be wary of this if you inspect
the return value of run or sudo!

For situations requiring the pty behavior turned off, the --no-pty
command-line argument and always_use_pty env var may be used.

As a final note, keep in mind that use of pseudo-terminals effectively implies
combining stdout and stderr – in much the same way as the combine_stderr setting does. This is because a terminal device naturally
sends both stdout and stderr to the same place – the user’s display – thus
making it impossible to differentiate between them.

However, at the Fabric level, the two groups of settings are distinct from one
another and may be combined in various ways. The default is for both to be set
to True; the other combinations are as follows:

run("cmd",pty=False,combine_stderr=True): will cause Fabric to echo all
stdin itself, including passwords, as well as potentially altering cmd‘s
behavior. Useful if cmd behaves undesirably when run under a pty and
you’re not concerned about password prompts.

run("cmd",pty=False,combine_stderr=False): with both settings
False, Fabric will echo stdin and won’t issue a pty – and this is highly
likely to result in undesired behavior for all but the simplest commands.
However, it is also the only way to access a distinct stderr stream, which is
occasionally useful.

run("cmd",pty=True,combine_stderr=False): valid, but won’t really make
much of a difference, as pty=True will still result in merged streams.
May be useful for avoiding any edge case problems in combine_stderr (none
are presently known).