Some might be confused by the changes to Fabric in 2.x. It's a complete rewrite and a complete API redesign.
Run local command (passing local environment)
c = fabric.Connection('visarend.solasistim.net')
c.local("/usr/bin/npm run build", replace_env=False)
Note the use of replace_env=True
, at the moment when you get a Connection from
fabric the environment is cleared for subprocesses, which can break many local
commands.
Upload binary data as file-like object
c = fabric.Connection('visarend.solasistim.net')
f = io.BytesIO(b"some initial binary data: \x00\x01")
c.put(f, 'out.bin')
Use plaintext authentication details
password = 'xyzzy'
connect_kwargs = {'password': password}
c = fabric.Connection('visarend.solasistim.net', connect_kwargs=connect_kwargs)
c.run('/bin/true')
Bundled sudo operations as part of file transfer
In the words of the Fabric developers,
This was one of the absolute buggiest parts of v1 and never truly did anything users could not do themselves with a followup call to sudo, so we opted not to port it.
This mouthful will do it:
import hashlib
import fabric
import shlex
class RemoteTemporaryPath(object):
# public name attribute designed to be retrieved by user
name = None
def __init__(self, c, remote_path):
hasher = hashlib.sha1()
hasher.update(c.host.encode('utf-8'))
hasher.update(remote_path.encode('utf-8'))
self.name = hasher.hexdigest()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
c.run("rm -rf {}".format(shlex.quote(self.name)))
def put_with_sudo(c, local_path, remote_path):
with RemoteTemporaryPath(c, local_path) as r:
c.put(local_path, r.name)
c.sudo("mv {} {}".format(shlex.quote(r.name), shlex.quote(remote_path)), password='xyzzy')
c = fabric.Connection('visarend.solasistim.net')
put_with_sudo(c, "foo.py", "/etc/foo.py")
A very important thing here: you need to decide at script time whether you will
respond to the sudo authentication prompt by hand or if you will use some other
method to get the sudo password. Here we are taking the approach of "use some
other method". If you need to respond to the sudo prompt by hand, you need to
use c.run("sudo foo", pty=True)
instead of c.sudo("foo", password='bar')
.
NB: I don't claim this code is 100% safe, please be careful.