5
\$\begingroup\$

I wrote this to learn exactly how paramiko worked in Py3. Also to keep as a code snippet for future work-related scripts. I know it can be tweaked and I'm hoping you experienced folks can help with that. I left the commented out lines for 'passwd' because not all hosts I connect to will use pubkeys.

import sys, paramiko, getpass


user = input("Username:") #Prompts for username
#passwd = getpass.getpass("Password for " + user + ":") #Prompts for password
key_file = input("Public key full path:") #Prompts for full path to key file
name = input("Target Hostname:") #Prompt for target hostname
command = input("Enter target command:") #Prompt for remote command


#Calling the paramiko ssh function
ssh = paramiko.SSHClient() #Define value 'ssh' as calling the paramiko.sshclient
print('calling paramiko')
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #Must come before connect line to add hosts to known_hosts
#ssh.connect("name", username="user", password="passwd")
ssh.connect(hostname = name, username = user, key_filename = key_file) # key_filename means to specify the actual file, pkey on the
#other hand means to actually paste in the key text itself
print('trying to connect')
ssh.invoke_shell()
stdin, stdout, stderr = ssh.exec_command (command)
print(stdout.read())
#ssh.close()
\$\endgroup\$
1
  • \$\begingroup\$ thanks for sharing this. I have a question, what do you mean with key_filename = key_file? is it the file which contains the password ? or its a file where the output will be stored. Thanks! \$\endgroup\$
    – esmael
    Jan 7, 2019 at 14:05

2 Answers 2

5
\$\begingroup\$

All your imports should be below eachother like this:

import sys
import paramiko
import getpass

I think using classes is a bit too much for this, but you should create a few functions to diverse functionality

  • A Main
  • A function for the shell commands
  • A function for connecting

This should be enough for now, you can always add more. Secondly when using comments they should be like this

# A comment
print('do something')

instead of this:

print('do something') # A comment

I do think you have too many comments because the names kind of speak for themselves

def ssh_command(ssh):
    command = input("Command:")
    ssh.invoke_shell()
    stdin, stdout, stderr = ssh.exec_command(command)
    print(stdout.read())

def ssh_connect(host, user, key):
    try:
        ssh = paramiko.SSHClient()
        print('Calling paramiko')
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(hostname=host, username=user, key_filename=key)

        ssh_command(ssh)
    except Exception as e:
        print('Connection Failed')
        print(e)

if __name__=='__main__':
    user = input("Username:")
    key = input("Public key full path:")
    host = input("Target Hostname:")
    ssh_connect(host, user, key)

I think your program is ok, but could use some improvement, be sure to check out the Paramiko demo's these contain many usefull pointers for working with parmiko

\$\endgroup\$
3
  • \$\begingroup\$ Thanks for this.. is there a benefit to not combining the imports? I see plenty of both ways on the internets. I did think the same about the number of comments.. but in this case, being used as a snippet moving forward I was not worried. \$\endgroup\$
    – Skeer
    Jul 26, 2017 at 14:54
  • \$\begingroup\$ About the inports it's considered good style... when programming it's good to hold on to a styling guide. I think PEP8 is a good reference guide \$\endgroup\$
    – Ludisposed
    Jul 26, 2017 at 14:58
  • \$\begingroup\$ Makes perfect sense. \$\endgroup\$
    – Skeer
    Jul 26, 2017 at 22:52
2
\$\begingroup\$
  • First thing I would do is to refactor your code and redesign it following the functional or OOP concepts. As it is right now, your code is shaped according to an old school of doing things (sequential programming).

  • Personally, I would remove all your comments because they are distracting and they bring noise to your code. For the comments you really think can be useful, you will need to write them in in a better way. You can take the example of that comment following your SSH socket: it is a too long comment that need to span in multiple shorter lines instead, and put before that instruction.

  • There are also few details you need to pay attention to: for example, lines can not be left empty randomly just like that. Also, the space between operands is better to avoid when passing arguments to a function (For example, write ssh.connect(hostname=name, username=user, key_filename=key_file) instead of ssh.connect(hostname = name, username = user, key_filename = key_file) and stdin, stdout, stderr = ssh.exec_command(command) instead of stdin, stdout, stderr = ssh.exec_command (command)
\$\endgroup\$
4
  • \$\begingroup\$ IMO, for something small as this, there's no benefit in OO and functional would only hurt in the long run. \$\endgroup\$
    – Mast
    Jul 26, 2017 at 7:59
  • \$\begingroup\$ Functional and OOP concepts are not useful when we do not think about scalability \$\endgroup\$ Jul 26, 2017 at 8:11
  • \$\begingroup\$ We got functions for that, I'm perfectly aware of how scalability works. \$\endgroup\$
    – Mast
    Jul 26, 2017 at 9:10
  • \$\begingroup\$ Thanks for the suggestions.. like I said above this was more to prove that I could get it work work. It def would not be used in a production setting like it is ;) \$\endgroup\$
    – Skeer
    Jul 26, 2017 at 14:57

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.