How to stop a blocking process using SSH as a subprocess - python

What I actually tried to do:
Using a python script to start a nc(netcat) on a remote host using SSH. This netcat should listen for incoming TCP connections. It could be possible that no one wants to connect to the remote host so the netcat process have to be killed.
My first idea was using the PID of the nc process on the remote host and execute a simple kill [PID] command. But I was not able to get the process id from the nc process on the remote host.
What I have tried so far was using paramiko and sshpass.
My paramiko code:
import os, sys, paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, username=user, password=password)
stdin, stdout, stderr = ssh.exec_command("nc -l -p"+port+"&")
print stdout.readlines()
Using sshpass:
sshProcess = subprocess.Popen(["sshpass", "-p", password, "ssh", user+"#"+hostaddress, "nc", "-l", "-p", str(destPort),"&"], stdout=subprocess.PIPE, stdin=None)
print sshProcess.stdout.read()
I tried the sshpass approach on the normal linux terminal and the pid of the netcat process was returned. But trying both approaches in a python script had the same result: the whole script was blocked instead of returning the PID. If I do not try to read the output -- that means deleting the stdout.readlines() or sshProcess.stdout.read() -- the scripts are not blocked but I also do not get the PID of the netcat process on the remote host.
I am working on a Linux machine and the remote host also runs Linux.

Remove "&" to execute nc synchronously with ssh -t then to kill nc just kill the subprocess (p.terminate()).
See how to stop reading the subprocess stdout on timeout.

Related

Paramiko exec_command does not execute the command

What is the way to run a .bat (or Python) script on a remote Windows server 2016? SSH server is installed and works correctly.
I tried using Paramiko, but it didn't bring any result:
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('ip', username='root', password='pass')
ssh_stdin, ssh_stdout, ssh_stder = ssh.exec_command('C:/Users/Administrator/Desktop/main/videos/uniq.bat')
What am I doing wrong? The script does not run. However, if you run it manually, it works well.
The batch file is:
FOR /F "tokens=*" %%G IN ('dir /b *.mp4') DO ffmpeg -i "%%G" -vf noise=alls=1:allf=t "%%~nG_1.mp4"
The SSHClient.exec_command only starts an execution of the command. If you do not wait for it to complete and immediately kill the session, the command is killed along with it.
The most trivial way to wait for command to complete is reading its output to the end:
stdin, stdout, stderr = ssh.exec_command(command)
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
If this won't fix the problem on its own, it will at least collect any error output to help you identifying the (other) problem.

How to ssh to a remote linux server using python script and be able to execute command as the user specified while using ssh in the python script

I have to monitor 8 to 9 servers. I am thinking of creating a python script that will create a menu to login to any servers and after using ssh to login to the server, can I be able to execute commands in the server as the 'user' specified in the ssh. Please see the command below in python. I am importing 'os' to execute the bash commands.
server_login = "ssh {}#{}".format('user_name','10.111.0.10')
os.system(server_login)
you can install paramiko for this
pip install paramiko
then the script can be like
import paramiko
host = "google.com"
port = 22
username = "user"
password = "Pass"
command = "ls"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port, username, password)
stdin, stdout, stderr = ssh.exec_command(command)
lines = stdout.readlines()
print(lines)
If paramiko isn't your style, I can think of two other ways to do this:
run the command: ssh <user>#<host> <command> for every command via os.system calls. This gets rather cumbersome when you're using passwords for SSH instead of keys.
run ssh <user>#<host> with the subprocess library instead so you can get access to stdin and stdout and run multiple commands in the session
import subprocess
p = subprocess.Popen(['ssh','root#example.com'], stdout=PIPE, stdin=PIPE)
p.stdin.write("ls\n")
print(p.stdout.read())

Paramiko ssh connection to windows host. Empty stdout of "VBoxManage.exe guestcontrol run" command

I'm writing python script executing bash script inside virtualbox VM using paramiko python library. The code snippet below:
stdin, stdout, stderr = i[2].exec_command("\"\Program Files\Oracle\VirtualBox\VBoxManage.exe\" guestcontrol \"virtnet_proxy\" run --exe \"/home/username/show_ip.sh\" --username username --password password" )
exit_status = stdout.channel.recv_exit_status()
if exit_status == 0:
proxy_ip=stdout.readlines()
print ("got proxy ip from host ", i[0], proxy_ip, stderr.readlines())
Connects to windows host and
should print ip address of a VM's interface. If you run this command in cmd it works fine but using paramiko ssh client, stdout is empty. If you run similar code except you connect to linux virtualbox host (and run linux command) stdout.readlines() works fine and contains output of bash script. Stderr output:
VBoxManage.exe: warning: Error getting stdout handle: VERR_NOT_IMPLEMENTED\r\n', 'VBoxManage.exe: warning: Error getting stderr handle: VERR_NOT_IMPLEMENTED\r\n
Bash script:
ips=$(hostname --all-ip-addresses)
read -ra arr <<< "$ips"
echo"${arr[0]}"
As i said stdout is empty only if you connect to windows host and run vboxmanage command on guest machine.
Thank You in advance,
Wojtek
EDIT: I've changed ssh server on windows host from OpenSSH to FreeSSHd and the code worked !

SSH from my local machine to linux host and sudo to root user

Used subprocess to ssh to host.
Here is the code snippet i used to ssh and run commands as my user. When i try to use sudo command i get error related to tty -- not a terminal (something like that)
sshProcess = subprocess.Popen(['ssh', hostname], stdin=subprocess.PIPE, stdout = subprocess.PIPE, universal_newlines=True, bufsize=0)
sshProcess.stdin.write("hostname\n")
sshProcess.stdin.write("ls -ldr %s \n"%path)
sshProcess.stdin.write("pwd \n")
sshProcess.stdin.close()
for line in sshProcess.stdout:
if line == "END\n":
break
print(line,end="")
But i am not able to run below command
sshProcess.stdin.write("sudo su - serviceuser \n")
You can force a pseudo-tty allocation by specifying -t option.
subprocess.Popen(['ssh -t', hostname], .....
From man ssh
-t
Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t optionsforce tty allocation, even if ssh has no local tty.

Unable to see ifconfig output using paramiko

I am using below code to execute commands on a remote machine,
import paramiko
import os
dssh = paramiko.SSHClient()
dssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
dssh.connect('192.168.1.5', username='root', password='asdfghhh')
import os
stdin, stdout, stderr = dssh.exec_command('ls')
print stdout.read()
stdin, stdout, stderr = dssh.exec_command('ifconfig')
print stdout.read()
stdin, stdout, stderr = dssh.exec_command('ps')
print stdout.read()
dssh.close()
when I execute the program, Its able to show the ls and ps as well as other commands output.
however ifconfig o/p is not observed.
any idea how to solve this problems?
Thanks in advance...
Your server may be discriminating between interactive and non-interactive SSH sessions, running different startup scripts for the different sessions. Try running echo $PATH on the remote host through the paramiko SSH session and a regular interactive one and compare the outputs.
For a workaround you can do a which ifconfig on the remote server in an interactive session to get the absolute path and use that in your paramiko command.
stdin, stdout, stderr = dssh.exec_command('/abs/path/to/ifconfig')
NOTE
On one of my hosts the result of echo $PATH from the paramiko SSH client was /usr/bin:/bin, while in an interactive session it was /usr/local/sbin:/usr/sbin:/usr/bin:/sbin:/bin, and ifconfig was indeed located in /usr/sbin, i.e. outside the path of the paramiko session.
To get the output for certain application binaries you must use the flag: get_pty=True
I'm still looking for the reason it happens for some commands, it's for me unknown yet. However the way I found to workaround this problem is shown in the example below:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('10.2.0.230', username='ibmsys1', password='passw0rd', timeout=5)
stdin, stdout, stderr = ssh.exec_command('/sbin/ifconfig', timeout=3, get_pty=True)
print stdout.read()
Usually I would run:
#stdin, stdout, stderr = ssh.exec_command('/sbin/ifconfig')
in my example, I've just added 2 new flags, timeout=3 and get_pty=True
This solved my problem. The timeout flag is not related, however I always use it as good practice. The point here is the use of the get_pty=True
PS. I would recommend do not trust on the system $PATH, always input the full path for the application to be run, e.g: /usr/bin/my_binary or in your case /sbin/ifconfig
I hope this may help you to workaround the problem.
Good luck!

Categories

Resources