Paramiko parallel execution to the remote unix hosts - python

I have a below script which i'm using to execute commands on remote hosts as a cetralized user, but this script is reads the host file and execute the command one by one however it also remains on the session until its not unlinked from the shell, Hence i want to have a parallel execution saying that when running the script it should be able to fork multiple ssh connection and login to the host and exit immeadiaely after command execution.
Please let me know if you guys have any trick or expert inputs. Though i'm using paramiko as these hosta rae legarcy UNIX hosts where i'm unable to use ansible or like utilities due to some restrictions.
import paramiko
with open('/data/CR9432/SunOS.txt', 'r') as f:
for host in f:
remote_host = host.rstrip()
remote_pass = "pass123"
smart_user = "mtrooper"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(remote_host, username=smart_user, password=remote_pass)
transport = ssh.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
#for testing purposes we want to force sudo to always to ask for password. because of that we use "-k" key
############################################
#session.exec_command("shutdown -y -i5 -g0")
############################################
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
#you have to check if you really need to send password here
stdin.write(remote_pass +'\n')
stdin.flush()
print"\n"
print "------------------------------------------------------------------------------"
print "Command Execution Output On Hostname: "
print "------------------------------------------------------------------------------"
for line in stdout.read().splitlines():
print 'host: %s: %s' % (remote_host, line)

Related

Failing to start an .exe to a remote Windows server using Python and paramiko

I have written a simple script that I want to run remotely to a Windows server using Python and Paramiko. The script should execute commands in the cmd on the remote Windows server and I want it to start up an .exe program for a starter. Here is what I have up to now:
import paramiko
hostname = "IP_of_server"
username = "username"
password = "password"
command = "start Full_Path_To_Application\Program.exe"
try:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname, username=username, password=password, look_for_keys=True, allow_agent=False)
print("Connected to %s" % hostname)
except paramiko.AuthenticationException:
print("Failed to connect to %s due to wrong username/password" %hostname)
exit(1)
try:
stdin, stdout, stderr = ssh.exec_command(command)
for line in stdout.readlines():
print(line)
print("Application has been started")
except:
exit(2)
What I get is:
Connected to IP_of_server
Application has been started
When I check on the server using the same username and password the application is not running. Running it manually starts it up.
I have confirmed that the command has been sent to the server by replacing it with "ipconfig" and I get the correct information.
Any idea why the application is not starting? Once it starts it should open a separate cmd with all the logs that I'm not seeing.
Thanks a lot.

SSH tunnel with terminal

I'm a beginner at ssh so be kind with my limited knowedge ;)
What I want to do is as follow:
SSH to a PC and then from this PC SSH to another one, see picture below:
SSH Tunnel
Here are the commands I run when I do it manually:
ssh user#155.254.0.1
After this command I will be prompt to enter the password.
From here I ssh again to the next "PC" with the following command:
ssh root#190.22.0.1 -y
and then I get prompt to enter the password.
I tried to use a python script to do it automatically by I was not able to come to the next seconds step.
Here is how the python code looks like:
import subprocess
cmd_1 = ["ls"]
cmd_3 = ['ls', '-l']
def send_top_cmd():
cmd_2 = ['top', "-b", "-n", "5"]
com2 = subprocess.Popen(cmd_2, stdout=out)
com2.wait()
def send_ssh_pc_1():
cmd = ["sshpass", "-p", "'user'", "ssh", "swupdate#155.254.0.1"]
ssh_sga = subprocess.Popen(cmd, stdout=out)
ssh_sga.wait()
def send_ssh_pc_2():
cmd = ["sshpass", "-p", "'root'", "ssh", "root#190.22.0.1"]
ssh_hpa = subprocess.Popen(cmd, stdout=out)
ssh_hpa.wait()
def send_exit():
cmd = ["exit"]
process = subprocess.Popen(cmd, stdout=out)
cmd = ["exit"]
process = subprocess.Popen(cmd, stdout=out)
print("done")
with open('output.txt', 'w') as out:
send_ssh_pc_1() # ssh PC 1
send_ssh_pc_2() # ssh PC 2
send_top_cmd() # Send a simply command
send_exit()
The script fails at the "send_ssh_pc_2()" since I dont have sshpass installed and there's no possibility to install it there :(
Is there a easier way to do it automatically?
So much easier to write as an answer instead of comment.
First, enable RSA authentication for both of your SSH boxes. Then you don't need to worry about passing password. https://www.ssh.com/academy/ssh/public-key-authentication
Then open SSH tunnel from your computer with following command:
ssh -L 2222:190.22.0.1:22 user#155.254.0.1
That will enable tunnel from your local computer port 2222 to host in address 190.22.0.1 port 22. So next you can open SSH connection to the target computer like this.
ssh -p 2222 root#localhost
If your RSA private key is authorized to both user#155.254.0.1 and root#190.22.0.1 no passwords should be asked and you have SSH connection to 192.22.0.1 from your workstation.
Of course you can tunnel any TCP traffic, not just SSH.
*** ADDED ***
Here is example of content of authorized_keys -file (some content removed).
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3fauf5H3kN92Gxx8xerCF***********************************************************************************************************************PPIrUMdf1948pqLspom8SIyeqJeKX8wVqcJch35O0Q4UVlbw== user#host
ssh-rsa AAAAB3Nzaasdfrgaa4634w4gfdewrtfauf5H3kN92Gxx8xerCF***********************************************************************************************************************PPIrUMdf1948pqLspossdfgqrbbsrdtwetdsfgsfdgsd== admin#anotherhost

'Error opening terminal: unknown.' error when running a command in SSH server through Python

I am trying to SSH to a server with Python and I have been able to do so successfully. I am able to run the commands within Python successfully with one exception, the main command that is the focus of my program. It is a SIPp command that will only run within the SSH server and in a specific folder.
When I run the command in my terminal, it works perfectly fine; however, when I connect to the SSH server through PExpect or Paramiko (both work fine), I try to send my command but I get the
Error Opening Terminal: Unknown
I have so far, read the docs, tried using os, subprocess, and multiple different ways of connecting with Paramiko and Pxssh. The several people I work with were not able to figure it out either.
The SIPp command that I am trying to send and read the output of:
sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]
# some of the command was left out for simplicity's sake
# there is no issue with the command
Connecting to SSH through Pxssh (PExpect):
from pexpect import pxssh
from getpass import getpass
try:
s = pxssh.pxssh()
hostname = input('hostname: ')
username = input('username: ')
password = getpass("password :", None)
s.login(hostname, username, password)
s.sendline('cd [location of the folder]')
s.prompt()
print(s.before)
s.sendline('sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]') #this is the only line that doesn't work / output anything.
s.prompt()
print(s.before)
s.sendline('ls')
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("Something went wrong. Try again with the correct Host Name, Username, and Password")
print(e)
Connecting to SSH through Paramiko:
from paramiko import client
from getpass import getpass
class ssh:
client = None
def __init__(self, address, username, password):
self.client = client.SSHClient()
self.client.set_missing_host_key_policy(client.AutoAddPolicy())
self.client.connect(address, username=username, password=password, look_for_keys=False)
def sendCommand(self, command):
if self.client:
stdin, stdout, stderr = self.client.exec_command(command)
output = stdout.readlines()
print(output, stderr.readlines())
while not stdout.channel.exit_status_ready():
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print(str(alldata, "utf8"))
self.client.close()
else:
print("Connection not opened.")
connection = ssh([ssh info])
connection.sendCommand("cd [location] ; sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]")
Both give me this error: Error opening terminal: unknown.
My guess is that it is not spawning an actual terminal but I can't figure out what to do at this point. Any help would be sincerely appreciated
Your command needs terminal emulation.
Either:
Try to find if there's a way to run the command, so that it does not require the terminal emulation. Maybe -bg switch can help.
Possibly this was a bug in an older version of SIPP. Make sure you have the latest version. See Startup failure when running from environment without TERM.
Or, enable the terminal emulation (what can bring unwanted side effects). With Paramiko SSHClient.exec_command, use its get_pty argument:
stdin, stdout, stderr = self.client.exec_command(command, get_pty=True)

Printing real-time SSH output using Python 3.x

I have a script that SSH connects from Windows7 to a remote ubuntu server and executes a command. The script returns Ubuntu command output to the Windows cmd window in one go after the command has executed and finished. I am just wondering if there is anyway to return real-time SSH output in my script below, or do I always have to wait for the command to finish before seeing the output.
Here's my working code:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
host = '9.10.11.12'
port, user, password = 22, 'usr', 'pass'
ssh.connect(host, port, user, password)
stdin,stdout,stderr = ssh.exec_command("cd /opt/app && ./app-tool some_command")
for line in stdout.readlines():
print(line)
ssh.close()
Alternatively, if this is not possible with SSH how would I introduce a spinning cursor icon into the above script? Thanks.
Figured it out in the end, I used 'iter' method in the following line:
for line in iter(stdout.readline,""):
print(line)
The output of your command seems to less than the default buffer size because of which it is getting flushed once the command completes.
By default the bufsize is -1 which means that the system default buffer size is used. If bufsize is set to 1 then it is line buffered.
Use
ssh.exec_command("<cmd>",bufsize=1)

Automating SSH using Python

I have this 30 virtual machines and I am doing everything manually right now which is a kind of trouble for me. I am trying now to write a script so I can connect to them all automatically and do my desired task. I made a flow diagram of what I need to do. Can anybody just give me some hints on how will i achieve this task programatically. I am attaching the flow diagram.
Thanks in Advance.
Please Right Click On Image and Click View Image to See the Flow Diagram.
Reading a text file and getting the data is trivial:
with open('host.txt', 'r') as inf:
lines = inf.readlines()
hostlist = [ln.split() for ln in lines]
Now hostlist should be a list of lists;
[['192.168.0.23', 'root', 'secret'], ['192.168.0.24', 'root', 'secret2'] ...
But your list shouldn't have to contain more than the hostnames. IP adresses can be gotten from DNS that you have to configure anyway, and ssh can login without passwords if configured correctly.
Putting the passwords for all your virtual hosts in a plain text file has security concerns. If you want to go that route, make sure to restrict access to that file!
You can use subprocess to execute commands. I would suggest using rsync to push the desired files to the virtual machines. That minimizes network traffic. And you can deploy directly from filesystem to filesystem without having to roll a tarball. It can be as simple as
status = subprocess.check_output(['rsync', '-av', localdir, remotedir])
Where localdir is the directory where the files for the virtual machine in question are stored (it should end with a '/'), and 'remotedir' is the hostname::directory on the virtual machine where the data should land (this should not end with a '/').
For executing commands remotely, ssh is the way to go. Configure that for passwordless login, using ssh's authorized_keys file on each remote host. Then you don't need to put passwords in your list of hosts.
Fabric is best solution for you. Fabric based on paramiko ( which based on libssh2), it makes very easy to work with commands on remote host and provides function to upload and download fiels from remote host.
Here it is http://docs.fabfile.org/en/1.5/
Docs about put function here
I don't get your question in the flow diagram, however you can use paramiko as suggested and I have a large number of background utilities written on top of paramiko which enables support people to monitor remote web servers on the browser. Snippet below,
client = paramiko.SSHClient()
client.set_missing_host_key_policy( paramiko.AutoAddPolicy() )
client.load_system_host_keys()
client.connect( '192.168.100.1', port=4001, username='monitor', password='XXXX' )
cmds = [ "sed -i 's/\/bin\/date -u/\/bin\/date/g' /etc/cron.hourly/reboot" ]
for cmd in cmds:
if __DEBUG_MODE__:
print 'Executing..... ' + cmd
stdin, stdout, stderr = client.exec_command( cmd )
Also if you want to push files below is the snippet,
def setupSFTPClient(self, ip_add):
print 'Setting SFTP client: ' + ip_add
tb = 'Finished SFTP-ing. '
try:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.load_system_host_keys()
client.connect(ip_add, port=4001, username='monitor', password='XXXX')
sftp_client = client.open_sftp()
# NB you need the filename for remote path otherwise
# paramiko barfs with IOError: Failure
sftp_client.put( '/home/projects/portal_release.tgz', '/var/ND/portal_release.tgz' )
sftp_client.put( '/home/projects/portal_installer.sh', '/var/ND/portal_installer.sh' )
sftp_client.close()
except Exception, e:
print e
tb = traceback.format_exc()
finally:
print tb
client.close()

Categories