Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

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.

share|improve this question
1  
I think this is off-topic here. However for automation you might want to take a look at a higher-level library like Fabric. If you insist on passing data structures it would probably still be easier to store output in a file (and really, I'd say use a standard format like JSON, not the Python AST), transfer that, and then process it on your end. –  ferada Oct 30 '14 at 10:56
    
@ferada Thanks, Fabric looks good, I'll try to incorporate it. Is it really off-topic? I checked the tour and I thought it fits: "for sharing code from projects you are working on for peer review." –  confused00 Oct 30 '14 at 11:09
1  
Well, it sounds to me like this is more a question of how to do this in general, rather than a question of how the specific code can be improved (which is also just some snippets from the full code). In which case I'd say that the last test should rather be 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
    
That's very useful, thank you –  confused00 Oct 30 '14 at 11:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.