2

I'm building a program which sends commands to multiple servers with as less as possible user intervention. For this program, I use subprocess to send commands through SSH.

The interacted servers are many and dynamics. The program will be used mainly by my team members in my company. Most of the servers have the right file at /root/.ssh/authorized_keys and the program works great with them.

But some servers weren't installed well and we can't connect them using SSH without entering root password. The SSH password prompts hangs at the moment it needs to ssh.stdout.readlines() of the "problematic server".

How can I make sure the program will ignore, skip and keep going with the code each time it faces a server that prompts for root password because of keys issue and won't hang on the password prompt?

Here is my code:

#!/usr/bin/python
from socket import socket
import subprocess, os
def run_command():
ipList = input_ip_addresses() ### A function that receive from the user an infinite loop 
                              ### of ip addresses and then returns the ip addresses 
                              ### as a list.
print '\n Type Linux commands. Type "end" to finish entering commands.'
cmds = []
while True:
    userInput = raw_input("> ")
    if userInput.lower() == "end":
        break
    cmds.append(userInput)
print '\nThanks! Working...\n'
for ipAddr in ipList:
    badConnection = 0
    s = socket()
    s.settimeout(2)
    for currentPort in ("22", "22222"):
        print "INFO: Trying to connect to: {} with port {}".format(ipAddr, currentPort)
        try:
            portSocket = int(currentPort)
            s.connect((ipAddr, portSocket))
            s.close()
        except:
            badConnection += 1
            print "ERROR: Could not connect to {} with port {}".format(ipAddr, currentPort)
            if badConnection == 1:
                continue
        if badConnection == 2:
            break
        for cmd in cmds:
            ssh = subprocess.Popen(['ssh', ipAddr, "-p", currentPort], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, bufsize=0)
            finalCMD = "{} \n".format(cmd)
            ssh.stdin.write(finalCMD)
            ssh.stdin.close()
            sshOutput = ssh.stdout.readlines()
            sshError = ssh.stderr.readlines()
            if len(sshError) > 0:
                for msg in sshError:
                    print msg
            if len(sshOutput) > 0:
                for msg in sshOutput:
                    print msg
            if len(sshOutput) == 0 and len(sshError) == 0:
                msg = 'Command executed successfully'
                print msg
        break
    if badConnection == 2:
        continue

Additionally some servers work with port 22 and some with port 22222, so that is why the there is a "CurrentPort" condition.

3
  • Please remove all the superfluous empty lines from your code. This is unnecessarily hard to read. As far as I can tell, you forgot to actually ask a question (that is, a sentence with a question mark ? at the end that we can answer). Commented Aug 19, 2017 at 9:48
  • @MarcusMüller Thanks, I fixed it. Commented Aug 19, 2017 at 9:59
  • The BatchMode might be usefull: serverfault.com/questions/61915/… Commented Aug 19, 2017 at 13:06

1 Answer 1

3

ssh has several options to make batch processing better; man ssh is your friend, and no matter whether what I write below, you should definitely read it:

With the -o option, you can specify any option that you could have in your ssh_config. Again, documentation is your friend, and you should have read man ssh and man ssh_config. In your particular case, you'd want

['ssh', '-o', 'PasswordAuthentication=No', ipAddr, "-p", currentPort]

to completely disable Password-based logins.

Anyway, maybe you'd rather not want to spawn an SSH process for every connection, if this is a high throughput thingie. Have a look at python SSH libraries - paramiko seems to be the library of choice for the things you're trying to do!

Taking another step back to look at the thing you want to build: you're reinventing the wheel. Try ansible. It's exactly what you do – controlling lists of hosts, it's a bit focussed on system maintenance, so it's really easy to e.g. make lists of packages you want to have installed on every machine, modifications to config files to do, and services to start, without having too care about very much about target system details.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot! Adding the "PasswordAuthentication=No" did the job. Now I have an error of publickey,password but this kind of thing I know how to handle. Thanks again :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.