I have the following code in python:
import pxssh
s = pxssh.pxssh()
try:
if not s.login ('x.x.x.x', 'root', 'password'):
print "SSH session failed on login."
print str(s)
else:
print "SSH session login successful"
s.sendline ('uptime')
s.prompt() # match the prompt
print s.before # print everything before the prompt.
s.logout()
except pxssh.ExceptionPxssh, e:
print "SSH conection failed"
print str(e)
and I success to do ssh connection.
Now, I want to append a key to a file which already exists in my system (in /root/.ssh/authorized_keys)
I don't find any way to do it with the pxssh API. How can I do it.
In the following code I'll assume that you have successfully connected to the remote machine via ssh. I have used this method for a similar purpose but with different data.
file_data = open("/root/.ssh/authorized_keys").read()
"""manipulate the contents of the file such that the variable new_key contains
the data you want to append to the file via ssh"""
#I'll assume the data to be abcd
new_key = "abcd"
#Constructing the command to pass via ssh
cmd = 'echo "' + new_key + '">>/root/.ssh/authorized_keys'
#note that I've used >> and not >, the former will append while the later will overwrite the file
#also the path given in the above command is the one on the remote ssh server and not your local machine
s.sendline(cmd)
s.prompt()
print s.before
#voilà your key is appended to the file on the remote server
#you can check that
s.sendline("cat /root/.ssh/authorized_keys")
s.prompt()
print s.before
Hope this helps.
Related
I am having issues passing responses to a bash script on a remote server over SSH.
I am writing a program in Python 3.6.5 that will SSH to a remote Linux server.
On this remote Linux server there is a bash script that I am running which requires user input to fill in. For whatever reason I cannot pass a user input from my original python program over SSH and have it fill in the bash script user input questions.
main.py
from tkinter import *
import SSH
hostname = 'xxx'
username = 'xxx'
password = 'xxx'
class Connect:
def module(self):
name = input()
connection = SSH.SSH(hostname, username, password)
connection.sendCommand(
'cd xx/{}/xxxxx/ && source .cshrc && ./xxx/xxxx/xxxx/xxxxx'.format(path))
SSH.py
from paramiko import client
class SSH:
client = None
def __init__(self, address, username, password):
print("Login info sent.")
print("Connecting to server.")
self.client = client.SSHClient() # Create a new SSH client
self.client.set_missing_host_key_policy(client.AutoAddPolicy())
self.client.connect(
address, username=username, password=password, look_for_keys=False) # connect
def sendCommand(self, command):
print("Sending your command")
# Check if connection is made previously
if (self.client):
stdin, stdout, stderr = self.client.exec_command(command)
while not stdout.channel.exit_status_ready():
# Print stdout data when available
if stdout.channel.recv_ready():
# Retrieve the first 1024 bytes
alldata = stdout.channel.recv(1024)
while stdout.channel.recv_ready():
# Retrieve the next 1024 bytes
alldata += stdout.channel.recv(1024)
# Print as string with utf8 encoding
print(str(alldata, "utf8"))
else:
print("Connection not opened.")
The final /xxxxxx in class Connect is the remote script that is launched.
It will open a text response awaiting a format such as
What is your name:
and I cannot seem to find a way to properly pass the response to the script from my main.py file within the class Connect.
Every way I have tried to pass name as an argument or a variable the answer seems to just disappear (likely since it is trying to print it at the Linux prompt and not within the bash script)
I think using the read_until function to look for the : at the end of the question may work.
Suggestions?
Write the input that your command needs to the stdin:
stdin, stdout, stderr = self.client.exec_command(command)
stdin.write(name + '\n')
stdin.flush()
(You will of course need to propagate the name variable from module to sendCommand, but I assume you know how to do that part).
I'm trying to open a file which got created as part of the Paramiko exec_command. The file gets created, but when I check if the file exists, it always returns false. How do I check if the file exists and then open the file for reading?
The code written is:
ip = '10.30.2.104'
username = 'root'
password = 'docker'
def checkSSH(ip, username, password, retries=1):
ssh = SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.load_system_host_keys()
for x in range(retries):
try:
ssh.connect(ip, username=username, password=password, timeout=10)
return ssh
except (
paramiko.BadHostKeyException, paramiko.AuthenticationException, paramiko.SSHException, socket.error) as e:
print('Exception occured.. {0}'.format(e))
return False
hdl = checkSSH(ip, username, password)
cmd = 'ls > test.log'
hdl.exec_command(cmd)
a = os.path.exists('/root/test.log')
print(a) >>> if the file exists, this returns true as per the documentation but in this case, it always returns false.
First, you are not waiting for the command to complete.
For that see:
Wait to finish command executed with Python Paramiko
Once the command completes, you can retrieve its exit code using Channel.recv_exit_status():
How can you get the SSH return code using Paramiko?
If it returns 0, you know that everything went fine and no additional check is needed.
Anyway, if you want to check, use SFTP (SFTPClient.stat):
sftp = hdl.open_sftp()
try:
sftp.stat('/root/test.log')
print("exists")
except Exception as e:
print("something is wrong: " + e)
Though the execution of ls command seems strange to me.
If you want to retrieve the directory listing, use SFTP: SFTPClient.listdir_attr
So I built a program that prints out the login logs of my ubuntu server using tail -f.
The program uses Paramiko to connect via ssh and runs the command to tail the logs.
The program works but it prints out the motd from the server which is unnecessary.
I've tried splicing using itertools.
Tried using next().
Still doesn't work.
Here's my code:
import yaml, paramiko, getpass, traceback, time, itertools
from paramiko_expect import SSHClientInteraction
with open("config.yaml", "r") as yamlfile:
cfg = yaml.load(yamlfile, Loader=yaml.FullLoader)
def main():
command = "sudo tail -f /var/log/auth.log"
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
server_pw = getpass.getpass("Enter the password for your account %s on %s:" % (cfg['ssh_config']['username'], cfg['ssh_config']['host']))
sudo_pw = getpass.getpass("Enter the sudo password for %s on %s: " % (cfg['ssh_config']['username'], cfg['ssh_config']['host']))
ssh.connect(hostname = cfg['ssh_config']['host'], username = cfg['ssh_config']['username'], port = cfg['ssh_config']['port'], password = server_pw)
interact = SSHClientInteraction(ssh, timeout=10, display=False)
interact.send(command)
interact.send(sudo_pw + "\n")
with open(interact.tail(line_prefix=cfg['ssh_config']['servername']+': ')) as tail:
for line in itertools.islice(tail, 17, None):
print(line)
except KeyboardInterrupt:
print('Ctrl+C interruption detected, stopping tail')
except Exception:
traceback.print_exc()
finally:
try:
ssh.close()
except:
pass
if __name__ == '__main__':
main()
You get MOTD because you are opening an interactive shell session. I do not think you need that, quite on the contrary.
Use SSHClient.exec_command instead:
stdin, stdout, stderr = ssh.exec_command(command, get_pty=True)
stdin.write(sudo_pw + "\n")
stdin.flush()
for line in iter(stdout.readline, ""):
print(line, end="")
Related questions:
Get output from a Paramiko SSH exec_command continuously
Pass input/variables to command/script over SSH using Python Paramiko
What is the difference between exec_command and send with invoke_shell() on Paramiko?
Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
I'm no programmer, but I try modify the following script.
http://www.networking-forum.com/wiki/Python_SSH_Script
I would like to make the script a bit more efficient.
At the moment the for loop makes the script do a new login for each command.
I would like the script do one login for each device and run all commands with one output for each device.
Here is the for loop:
# This function loops through devices. No real need for a function here, just doing it.
def connect_to(x):
for device in x:
# This strips \n from end of each device (line) in the devices list
device = device.rstrip()
# This opens an SSH session and loops for every command in the file
for command in commands:
# This strips \n from end of each command (line) in the commands list
command = command.rstrip()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(device, username=username, password=password)
stdin, stdout, stderr = ssh.exec_command(command)
output = open(device + ".out", "a")
output.write("\n\nCommand Issued: "+command+"\n")
output.writelines(stdout)
output.write("\n")
print "Your file has been updated, it is ", device+".out"
ssh.close()
connect_to(devices)
f1.close()
f2.close()
# END
After looking at the correct indentation found on your source check out the modifications below. This was inspired from this SO answer.
NOTE I do not have a target to ssh into and test these modifications.
def connect_to(x):
for device in x:
# Connect to the target
device = device.rstrip()
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(device, username=username, password=password)
# Open up a stream for the conncction
channel = ssh.invoke_shell()
ssh_stdin = channel.makefile('wb')
ssh_stdout = channel.makefile('rb')
output = open(device + ".out", "a")
# Send all of the commands to the open session
for command in commands:
# This strips \n from end of each command (line) in the commands list
command = command.rstrip()
# send the command
ssh_stdin.write(command)
# Update the local log file
output.write("\n\nCommand Issued: "+command+"\n")
output.writelines(ssh_stdout.read())
output.write("\n")
print "Your file has been updated, it is ", device+".out"
# Close the connection after all of the commands have been issued
output.close()
ssh_stdin.close()
ssh_stdout.close()
ssh.close()
I am using two commands in paramiko python module "find" and "scp".
Find command is working fine and giving the correct output but scp is not giving any output.
I tried with following code:
import paramiko
class SSH:
def ssh_Connection(self):
try:
self.ssh = paramiko.SSHClient()
self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
self.ssh.connect('host_name',username='user',password='pass')
except Exception, e:
print "================================================"
print 'ERROR: Remote connection failed with %s' % e
print "================================================"
def ssh_Commands(self):
try:
stdin, stdout, stderr = self.ssh.exec_command('find /result/main/ -name "*new.txt*"')
for line in stdout:
a = line.strip('\n')
print a
if a:
cmd = 'scp -r %s redhat#192.168.56.32:/results/main/' % a
print cmd
stdin, stdout, stderr = self.ssh.exec_command(cmd)
print stdout.read()
print stderr.read()
self.ssh.close()
except Exception, e:
print "================================================"
print 'ERROR: Commands Execution failed with %s' % e
print "================================================"
if __name__ == "__main__":
a = SSH()
a.ssh_Connection()
a.ssh_Commands()
But this program is not working for me..
Throwing an error:
Host key verification failed.
lost connection
How can use scp in paramiko...any idea?
You can use SFTPClient of paramiko to copy files from local to remote server.
There is put method for of SFTPClient which will copy local file to the remote server.
The server (host_name) on which you are performing the commands doesn't have proper SSH access to the server you are trying to scp to (192.168.56.32), that's why it generates the error Host key verification failed (which means that the host key for 192.168.56.32 in the known_hosts file on host_name doesn't match the key that 192.168.56.32 is returning).
Either fix the host key, or try running scp like this:
scp -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -r %s ...
(also be aware that if the filenames contain spaces, your scp command will fail, use "%s" on your scp command line instead).