Python script to run background services over SSH - python

Summary: I am ssh'ing to a remote server and executing a fork1.py script over there which is shown below. But the trouble is that I want the processes to execute in the background, so that I can start multiple services.
I know we can use nohup, etc. but they are not working. Even when I use a & at the end, the process starts, but gets killed when the script terminates.
Here is the code:
import os
import sys
import commands
from var import key_loc
import subprocess
import pipes
import shlex
def check(status):
if status != 0:
print 'Error! '
quit()
else:
print 'Success :) '
file1=open('/home/modiuser/status.txt','a')
file1.write("Success :)\n")
if(sys.argv[1]=="ES"):
os.chdir('/home/modiuser/elasticsearch-0.90.0/bin/')
proc1=subprocess.Popen(shlex.split("nohup ./elasticsearch -p /home/modiuser/es.pid"))
if(sys.argv[1]=="REDIS"):
os.chdir('/home/modiuser/redis-2.6.13/src')
proc2=subprocess.Popen(shlex.split("./redis_ss -p /home/modiuser/redis.pid"))
if(sys.argv[1]=="PARSER"):
proc3=subprocess.Popen(shlex.split("nohup java -jar logstash-1.1.12-flatjar.jar agent -f parser.conf"))
file1=open('/home/modiuser/pid.txt','a')
file1.write("PARSER-"+str(proc3.pid)+"\n")
file1.write(str(proc3.poll()))
file1.close()
if(sys.argv[1]=="SHIPPER_TCP"):
proc4=subprocess.Popen(shlex.split("nohup java -jar logstash-1.1.12-flatjar.jar agent -f shipper_TCP.conf"))
file1=open('/home/modiuser/pid.txt','a')
file1.write("SHIPPER_TCP-"+str(proc4.pid)+"\n")
file1.close()
Where am I going wrong?

just try with
import os
os.system('python program1.py &') #this one runs in the background
os.system('python program2.py') #this one runs in the foreground

Related

Use Raspberry Pi 4B Terminal Command in Python Application

I am currently working on a small Python Application which turns a Raspberry Pi 4B into a 48 Channel Audio-Recorder. Basics work, but during Recording, I need a log file which tells me when recording started, which ALSA warnings occurred and when recording stopped.
The recorder can be started with this terminal command:
pi#raspberrypi:~ $ rec -q -t caf --endian little --buffer 96000 -c 48 -b 24 /home/pi/myssd-one/Aufnahmen/test.caf 2>&1 | tee /home/pi/myssd-one/Aufnahmen/logging.log
this records audio in the test.caf file and writes ALSA warnings to logging.log
So far so good.
The Python Program (which should run on a touchscreen with GUI so recording can easily started and stopped) takes care of variable audio-filenames (date-time-stamp) and controls an LED to show that recording is running.
This part of the code takes care of switching on and off:
#!/usr/bin/env python
from tkinter import *
import shlex
import os
import subprocess
import tkinter.font
import datetime
from gpiozero import LED
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(11, GPIO.OUT)
def ledToggle():
if led.is_lit:
led.off()
my_env = os.environ.copy()
my_env['AUDIODRIVER'] = 'alsa'
my_env['AUDIODEV'] = 'hw:KTUSB,0'
ledButton["text"] = "Turn Recorder on"
print ("recorder stops")
subprocess.Popen(['sudo', 'pkill', '-SIGINT', 'rec'], env = my_env, shell = FALSE, stdout=subprocess.PIPE)
else:
led.on()
my_env = os.environ.copy()
my_env['AUDIODRIVER'] = 'alsa'
my_env['AUDIODEV'] = 'hw:KTUSB,0'
ledButton["text"] = "Turn Recorder off"
print ("recorder starts")
##reference statement command line: "rec -q -t caf --endian little --buffer 96000 -c 48 -b 24 /home/pi/myssd-one/Aufnahmen/test.caf 2>&1 | tee /home/pi/myssd-one/Aufnahmen/logging.log"
command_line = shlex.split("rec '-q' '-t' 'caf' '--buffer' '96000' '-c 48' '-b 24' '/home/pi/myssd-one/Aufnahmen/test.caf' '"2>&1 | tee"' '/home/pi/myssd-one/Aufnahmen/logging.log'")
p1 = subprocess.Popen(command_line, env = my_env, shell = False, stdout=subprocess.PIPE)
I am trying to move the original command line statement into the subprocess.Popen command, to no success yet. The part where routing to the log file is done, fails. It looks as the initiating sox-application 'rec' tries to interpret it as part of its own parameter list, instead of interpreting it as a redirection of stdout and stderr to the log file. I appreciate some guidance in this issue.
Variable Filenames for audio files is already done, but for simplicity taken out of this code snippet.
Thanks Mark, I dived into this command line along your hint that it only can run with shell=True and this implied that it had to be written as a full statement without separating commas and escape quotes. Now it works. Actually, the shlex.split() becomes obsolete.

Bad Display Name when running Python script on boot with Touch Screen

Attempting to run a Python script on boot on Raspberry Pi 3B+ 1GB RAM, Raspbian, with a SunFounder 10" Touch Screen, - .log file returns "Bad display name'
Python script is 100% functional when run via Terminal / executable script / Thonny etc. Attempted to run at boot first via rc.local - created a service, enabled service, daemon-reload... etc. Did not work.
Tried to run as crontab, same result - .log output from crontab shows "Bad display name". Thought it was lack of Display Environment imported and declared within the Python script, so I added that - but on boot returns the same result.
This is the Python Script I'm using
#!/usr/bin/env python3
import RPi.GPIO as GPIO
import os
import sys
import webbrowser
import time
import subprocess
from pynput import keyboard
from Xlib.display import Display
#GPIO Readout
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
#GPIO Header Setup
header = 2
GPIO.setup(header, GPIO.IN)
#Omxplayer Commands
Loop = 'omxplayer -b --loop --no-osd -o hdmi /home/pi/Videos/PlanetEarth.mp4 > /dev/null'
Donation = 'omxplayer -b --no-osd -o hdmi /home/pi/Videos/Cartoon.mp4 > /dev/null'
KillPlayer = 'pkill omxplayer.bin'
KillForm = 'pkill chromium'
#Set Display Environment
new_env = dict(os.environ)
new_env['DISPLAY'] = ':0.0'
#Form Handling Required Below
#If Donation is successful, Stop Looping Video, Open Form in Chromium, Wait 60 seconds, Close Chromium, Restart Loop
def PullDownSuccess():
subprocess.Popen(KillPlayer, env=new_env, shell=True)
time.sleep(2)
webbrowser.open('<url>')
time.sleep(60)
subprocess.Popen(KillForm, env=new_env, shell=True)
time.sleep(2)
subprocess.Popen(Loop, env=new_env, shell=True)
#Inception
subprocess.Popen(Loop, env=new_env, shell=True)
#Terminate Loop with Escape Key or Manually Initiate Donation Success
def on_press(key):
if key == keyboard.Key.ctrl:
PullDownSuccess()
if key == keyboard.Key.esc:
subprocess.Popen(KillPlayer, shell=True)
#Keyboard Listener Module
with keyboard.Listener(
on_press=on_press) as listener:
listener.join()
#Donation Successful Do:
while True:
header_state = GPIO.input(header)
if header_state == GPIO.HIGH:
PullDownSuccess()
I am currently attempting to run this script on Boot via crontab with this line:
#reboot (/bin/sleep 10; /usr/bin/python3 /home/pi/Custom_Scripts/<script>.py > /home/pi/Custom_Scripts/cronjoblog 2>&1)
The error log file for crontab returns the following:
raise error.DisplayNameError(display)
Xlib.error.DisplayNameError: Bad display name ""
This error only exists when attempting to run script on boot up. Is the Display overriding the boot display permissions on Boot Up? What is keeping the script from running on the Display on boot up, but not when remotely executed? Thank you for your consideration.
Update: Still no solution. Display environment returns ":0.0' ... so far I have tried to remove
> /dev/null from #Omxplayer Commands
Replacing crontab startup line to:
DISPLAY=":0" /usr/bin/python3 /home/pi/Custom_Scripts/<script>.py
and
DISPLAY=":0.0" /usr/bin/python3 /home/pi/Custom_Scripts/<script>.py
And any possible combination of these.
Confirmed the script is not waiting for any background processes as I have added delay (time.sleep) up to 30 seconds, as well as returning IP addresses, etc.
Returns either Bad Display Name still OR "Can't connect to display ":0": b'Invalid MIT-MAGIC-COOKIE-1 key"
Still looking for a solution if anyone has one.
EDIT:
Fixed using /LXDE-pi/autostart. Answer below.
Try to add DISPLAY environment variable before calling your script:
DISPLAY=":0" /usr/bin/python3 /home/pi/Custom_Scripts/<script>.py
DISPLAY="/dev/null" /usr/bin/python3 /home/pi/Custom_Scripts/<script>.py
Have you tried a longer sleep?
If you try to get your ip adress during your startup script with (for example) :
import socket
def get_ip_address():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("8.8.8.8", 80))
return s.getsockname()[0]
you will get an errror like:
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 101] Network is unreachable
This is because at reboot network is not necessarily available. In order to make it available
see https://raspberrypi.stackexchange.com/questions/45769/how-to-wait-for-networking-on-login-after-reboot :
sudo raspi-config
then select option 3 Boot Options
then select option 4 Wait for network at boot
Once you have done that networking should not be an issue at reboot.
You get also check for other ways to enforce network setup before running your script take a look at :
https://askubuntu.com/questions/3299/how-to-run-cron-job-when-network-is-up
If there are unforeseen ramifications for using this method, I will update this thread accordingly. I fixed this issue just by adding two lines to the autostart file which resides in /etc/sdg/lxsession/LXDE-pi/autostart.
sudo nano /etc/xgd/lxsession/LXDE-pi/autostart
Add these two lines, do not modify the existing code.
sleep 5
#/usr/bin/python3 /home/pi/Custom_Scripts/<script>.py
My autostart file looks like this:
#lxpanel --profile LXDE-pi
#pcmanfm --desktop --profile LXDE-pi
#xscreensaver -no-splash
point-rpi
sleep 5
#usr/bin/python3 /home/pi/Custom_Scripts/<script>/py
Ctrl + O to write file
sudo reboot

SSH in bash mode

I am new to python. I am trying to enter two commands in my script.
1) script filename.txt
2) ssh xyz#xyz.com
My script stops after the 1st command in executed. When I exit out of bash the 2nd command is execute. I tried 2 different scripts both have the same issue.
1) Script-1
import os
import subprocess
from subprocess import call
from datetime import datetime
call (["script","{}.txt".format(str(datetime.now()))])
echo "ssh xyz#xyz.com"
2) Script-2
call (["script","{}.txt".format(str(datetime.now()))])
def subprocess_cmd(command):
process = subprocess.Popen(command,stdout=subprocess.PIPE, shell=True)
proc_stdout = process.communicate()[0].strip()
print proc_stdout
subprocess_cmd('ssh ssh xyz#xyz.com')

How to stop another already running script in python?

There is a way to start another script in python by doing this:
import os
os.system("python [name of script].py")
So how can i stop another already running script? I would like to stop the script by using the name.
It is more usual to import the other script and then invoke its functions and methods.
If that does not work for you, e.g. the other script is not written in such a way that is conducive to being imported, then you can use the subprocess module to start another process.
import subprocess
p = subprocess.Popen(['python', 'script.py', 'arg1', 'arg2'])
# continue with your code then terminate the child
p.terminate()
There are many possible ways to control and interact with the child process, e.g. you can can capture its stdout and sterr, and send it input. See the Popen() documentation.
If you start the script as per mhawkes suggestion is it a better option but to answer your question of how to kill an already started script by name you can use pkill and subprocess.check_call:
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-9", "-f", script])
Just pass the name to kill:
padraic#home:~$ cat kill.py
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-9", "-f", script])
padraic#home:~$ cat test.py
from time import sleep
while True:
sleep(1)
padraic#home:~$ python test.py &
[60] 23361
padraic#home:~$ python kill.py test.py
[60] Killed python test.py
Killed
That kills the process with a SIGKIll, if you want to terminate remove the -9:
padraic#home:~$ cat kill.py
from subprocess import check_call
import sys
script = sys.argv[1]
check_call(["pkill", "-f", script])
padraic#home:~$ python test.py &
[61] 24062
padraic#home:~$ python kill.py test.py
[61] Terminated python test.py
Terminated
That will send a SIGTERM. Termination-Signals
Just put in the name of the program NOT the path to your script.
so it would be
check_call(["pkill", "-f", "MotionDetector.py"])

running java program from python script

I am trying to use a python script to
1) getting the Pid of a java program and,
2) using that pid to run JVMRuntimeClient.class
but nothing is happening
Here is my script:-
import subprocess
import os
process = subprocess.Popen('java -cp .Workspace.TestProject.bin.VirtualMemorySimulatorPart3')
pid=str(process.pid)
os.popen('java .Workspace.TestProject.bin.JVMRuntimeClient -pid' + pid)
print(pid)
exit()

Categories

Resources