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()
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jul 26, 2017 at 5:32
\$\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\$ Commented 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

answered Jul 26, 2017 at 8:24
\$\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\$ Commented 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\$ Commented Jul 26, 2017 at 14:58
  • \$\begingroup\$ Makes perfect sense. \$\endgroup\$ Commented 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)
answered Jul 26, 2017 at 6:03
\$\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\$ Commented Jul 26, 2017 at 7:59
  • \$\begingroup\$ Functional and OOP concepts are not useful when we do not think about scalability \$\endgroup\$ Commented Jul 26, 2017 at 8:11
  • \$\begingroup\$ We got functions for that, I'm perfectly aware of how scalability works. \$\endgroup\$ Commented 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\$ Commented Jul 26, 2017 at 14:57

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.