I need to communicate between 2 machines through ssh
to do some processing on one of the machines, and at the end, transfer the output to the first machine. Given that I use the paramiko
library, I can only make one shell command on the machine I'm sshing to, so the way I do it is I put together a long string of commands separated by ;
and print the output to the stdout
which afterwards i convert to a Python data structure using the literal_eval
function from the ast
library.
Something like this:
ssh_connect.py
import paramiko
def create_connection(password, username=defaultusername):
hostname = 'xxx.xxx.xxx.xxx'
username = username
password = password
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, username=username, password=password)
return ssh
main_file.py
...
ssh_connection = ssh_connect.create_connection(password, username)
try:
data = fetch_data.get_all_information(
ssh_connection,
some,
other,
parameters)
except Exception as e:
raise ValueError(e)
...
fetch_data.py
....
# Start constructing the command that I'll be executing with my one-shot ssh call
go_to_extract_dir = 'cd {home}tars/;'.format(home=home_dir)
extract_archive = (r'tar -xzf $(pcregrep -Mho "{something}{other}.*?{day}(?:.*\n)*?~\K.*" $(ls | grep "{pattern1}\|{pattern2}\|{pattern3}"));').format(
something='some_keyword',
other='other_keyword',
...
)
decode_file = ' python {script} `ls | grep {pattern1}{pattern2} | grep -v decoded`;'.format(
script='parser.py',
...
)
...
...
clean_data = 'rm {home}tars/*DATA*;'.format(home=home_dir)
# Send the command and register the output
stdin, stdout, stderr = ssh.exec_command(go_to_extract_dir +
extract_archive + decode_file +
get_parsed_data + clean_data)
# Store all output in a dictionary
data = {}
# The output prints an item on each line that I need separately
data['output'] = ast.literal_eval(stdout.readline()))
data['something'] = ast.literal_eval(stdout.readline())
data['next'] = ast.literal_eval(stdout.readline())
...
if data:
return data
else:
raise ValueError('The query returned nothing')
I can tell this is an unfortunate solution, but not sure what's the best practice in this situation. I was thinking about serializing the output to a file, but I'd have to do another ssh
connection to fetch the file - or just output its contents to the terminal but then what's the difference between my method and serializing?
Should I use a different ssh
library that allows more commands? I tried pxssh
but it was too slow.
I can't grab some files and do all the processing on my machine, cause the processing is done upon very big files stored on the machine I'm sshing to.
I'm quite ashamed of this code and my programming skills, so I appreciate any tips on how to salvage this thing.
if not data: raise ...; return data
,ast.literal_eval(stdout.readline())
should be a function and string concatenation for command execution should rather use"&&".join(...)
because otherwise you'll ignore failed shell commands. – ferada Oct 30 '14 at 11:27