4
\$\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\$
  • \$\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 at 14:05
3
\$\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\$
  • \$\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 '17 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 '17 at 14:58
  • \$\begingroup\$ Makes perfect sense. \$\endgroup\$ – Skeer Jul 26 '17 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\$
  • \$\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 '17 at 7:59
  • \$\begingroup\$ Functional and OOP concepts are not useful when we do not think about scalability \$\endgroup\$ – Billal Begueradj Jul 26 '17 at 8:11
  • \$\begingroup\$ We got functions for that, I'm perfectly aware of how scalability works. \$\endgroup\$ – Mast Jul 26 '17 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 '17 at 14:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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