Python: asynchronically ssh to multiple servers and execute commands, then save result into database

Viewed 473

I've searched extensively on Google and stackOverflow but cannot find relevant answer. So asking here. Hope you can kindly demo how to do it.

My use case is as follows:

  1. User put in ip addresses in a django form field (e.g. 12.12.12.12, 13.13.13.13, 14.14.14.14)
  2. django take ips and ssh to those machines and execute predefined script
  3. if script runs successfully, then django saves the result to database
  4. django display each server's execution results (successful, failed)

I can achieve the above function using sync methods, but the wait time is unbearably long. Trying to use asyncio.run to improve it but tried and failed repetatively. :S Here is my code:

in views.py

def create_record(request):
    record_form = RecordForm()

    if request.method == 'POST':
        record_form = RecordForm(request.POST)
        if record_form.is_valid():
            ips = record_form.cleaned_data['ip'].split(',') 
            start_time = time.time()
            for ip in ips:
                record_form = RecordForm(request.POST)
                record = record_form.save(commit=False)
                record.ip = ip
                record = asyncio.run(run_script(record))  # this function ssh to server and execute commands
                if record is correct:
                    record.save()
                    messages.success(request, ip + ' execution success')
                else:
                    messages.error(request, ip + ' execution failed')
            total = time.time() - start_time
            print('total:', total)
            return redirect('create_record') 
    context = {'record_form': record_form}
    return render(request, 'record-form.html', context)

the run_script goes as:

async def run_script(record):
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        client.connect(record.ip, username='xxx', pass)
        ssh_stdin, ssh_stdout, ssh_stderr = await client.exec_command('{script.sh}')  #python complains await cannot be used here
        # process output
        for line in ssh_stdout:
            info = line.strip('\n')
    except Exception as e:
        print("Exception: ", e)

    client.close()
    record.info = info
    return record
1 Answers

I looked at Paramiko now but couldn't find any asynchronous features. https://github.com/paramiko/paramiko/pull/68 from 2012 they didn't accepted pull request

I think AsyncSSH could be best solution. Have you tried it?

Related