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()
-
\$\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– esmael2019年01月07日 14:05:23 +00:00Commented Jan 7, 2019 at 14:05
2 Answers 2
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
-
\$\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– Skeer2017年07月26日 14:54:57 +00:00Commented 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– Ludisposed2017年07月26日 14:58:49 +00:00Commented Jul 26, 2017 at 14:58
-
\$\begingroup\$ Makes perfect sense. \$\endgroup\$Skeer– Skeer2017年07月26日 22:52:52 +00:00Commented Jul 26, 2017 at 22:52
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 ofssh.connect(hostname = name, username = user, key_filename = key_file)
andstdin, stdout, stderr = ssh.exec_command(command)
instead ofstdin, stdout, stderr = ssh.exec_command (command)
-
\$\begingroup\$ IMO, for something small as this, there's no benefit in OO and functional would only hurt in the long run. \$\endgroup\$2017年07月26日 07:59:28 +00:00Commented Jul 26, 2017 at 7:59
-
\$\begingroup\$ Functional and OOP concepts are not useful when we do not think about scalability \$\endgroup\$Billal BEGUERADJ– Billal BEGUERADJ2017年07月26日 08:11:57 +00:00Commented Jul 26, 2017 at 8:11
-
\$\begingroup\$ We got functions for that, I'm perfectly aware of how scalability works. \$\endgroup\$2017年07月26日 09:10:08 +00:00Commented 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– Skeer2017年07月26日 14:57:08 +00:00Commented Jul 26, 2017 at 14:57