How to get back raw binary output from python fabric remote command?

Question:

I am using Python 3.8.10 and fabric 2.7.0.

I have a Connection to a remote host. I am executing a command such as follows:

resObj = connection.run("cat /usr/bin/binaryFile")

So in theory the bytes of /usr/bin/binaryFile are getting pumped into stdout but I can not figure out what wizardry is required to get them out of resObj.stdout and written into a file locally that would have a matching checksum (as in, get all the bytes out of stdout). For starters, len(resObj.stdout) !== binaryFile.size. Visually glancing at what is present in resObj.stdout and comparing to what is in /usr/bin/binaryFile via hexdump or similar makes them seem about similar, but something is going wrong.

May the record show, I am aware that this particular example would be better accomplished with…

connection.get('/usr/bin/binaryFile')

The point though is that I’d like to be able to get arbitrary binary data out of stdout.

Any help would be greatly appreciated!!!

Asked By: pooley1994

||

Answers:

I eventually gave up on doing this using the fabric library and reverted to straight up paramiko. People give paramiko a hard time for being "too low level" but the truth is that it offers a higher level API which is pretty intuitive to use. I ended up with something like this:

with SSHClient() as client:
  client.set_missing_host_key_policy(AutoAddPolicy())
  client.connect(hostname, **connectKwargs)
  stdin, stdout, stderr = client.exec_command("cat /usr/bin/binaryFile")

In this setup, I can get the raw bytes via stdout.read() (or similarly, stderr.read()).

To do other things that fabric exposes, like put and get it is easy enough to do:

# client from above
with client.open_sftp() as sftpClient:
  sftpClient.put(...)
  sftpClient.get(...)

also was able to get the exit code per this SO answer by doing:

# stdout from above
stdout.channel.recv_exit_status()

The docs for recv_exit_status list a few gotchas that are worth being aware of too. https://docs.paramiko.org/en/latest/api/channel.html#paramiko.channel.Channel.recv_exit_status .

Moral of the story for me is that fabric ends up feeling like an over abstraction while Paramiko has an easy to use higher level API and also the low level primitives when appropriate.

Answered By: pooley1994