How do I run a bash-script from a system service? - python

So I'm trying to launch a tmux screen from a bash script which will then host a (python) discordbot. That bash script should in turn be launched from a system service so that the discordbot always launches with the physical server itself.
It seems that it gets stuck somewhere for some reason... I've been looking for ages for a solution but haven't been able to find one.
Here is the system service output:
● ubuntubot.service - UbuntuBot
Loaded: loaded (/etc/systemd/system/ubuntubot.service; enabled; vendor preset: enabled)
Active: active (running) since Fri 2021-08-13 18:39:26 CEST; 1min 58s ago
Main PID: 27366 (tmux: server)
Tasks: 2 (limit: 19060)
Memory: 4.9M
CGroup: /system.slice/ubuntubot.service
├─27366 /usr/bin/tmux new-session -d -s ubuntubot
└─27367 -bash
Here is my service file:
[Unit]
Description=UbuntuBot
After=network.target
[Install]
WantedBy=multi-user.target
[Service]
Type=simple
ExecStart=/usr/bin/bash /home/flynn/Minecraft/CreativeServer/DiscordBot/launchbot.sh start
Restart=always
RestartSec=5
And this is my bash script:
#!/bin/bash
#This script launches the Ubuntubot in a different tmux screen
#Start tmux ubuntu-session:
/usr/bin/tmux new-session -d -s ubuntubot
#Start UbuntuBot
/usr/bin/tmux send-keys -t ubuntubot "python3 ~/Minecraft/CreativeServer/DiscordBot/Ubuntubot.py" Enter
Maybe this is a horrible way to do it i have honestly no idea... I just need some help cause this is taking me wayyy to long on my own:)

Related

Autostart and automatically restart Python Script Raspberry Pi

I know how to autostart a python script (or so I thought). But I want a programm or something, if my python script is not running anymore, it should start the script again. Has anyone a idea how to do this?
Edit:
I tried running it as a service but that didnt work.
import bluetooth
import pygame
pygame.mixer.init()
server_sock=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
port = 22
server_sock.bind(("",port))
server_sock.listen(1)
client_sock,address = server_sock.accept()
print ("Verbindung Hergestellt mit: ", address)
while True:
recvdata = client_sock.recv(1024)
print ("Nachricht bekommen: %s" % recvdata)
pygame.mixer.pause()
if (recvdata == b"h"):
sound = pygame.mixer.Sound('/home/maxi/Desktop/test.wav')
playing = sound.play()
if (recvdata == b"p"):
sound = pygame.mixer.Sound('/home/maxi/Desktop/test2.wav')
playing = sound.play()
if (recvdata == b"k"):
break
client_sock.close()
server_sock.close()
My startscript is:
[Unit]
Description=MaxiTest
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=/usr/bin/python3 /home/maxi/Desktop/btsound1.py
[Install]
WantedBy=multi-user.target
You can search more about how a python script can perform as a service or daemon. There are many solutions in this link:
How to make a Python script run like a service or daemon in Linux
Between all solutions, I prefer 3 of them (I'm not very familiar with raspberry-pi, so check compatibility):
Cronjob: You can create a cronjob for the script and the OS will run it every x seconds/minutes/... automatically and periodically.
Systemctl/Systemd: Create a custom service file for your script and start and enable it in Systemd. A complete guide is here:
https://medium.com/codex/setup-a-python-script-as-a-service-through-systemctl-systemd-f0cc55a42267
You chose systemd (after editing);
In /PATH_project/ create 2 bash scripts like this:
#!/bin/bash
# This is start.sh
cd /home/maxi/Desktop/
/usr/bin/python3 btsound1.py
And create stop.sh:
#!/bin/bash
for KILLPID in `ps ax | grep ‘myservice’ | awk ‘{print $1;}’`; do
kill -9 $KILLPID;
done
Then give execution permission to both files using:
chmod a+x start.sh
chmod a+x stop.sh
Then create a myservice.service file in /etc/systemd/system :
[Unit]
Description=myservice service
Wants=network-online.target
After=network.target network-online.target
[Service]
Type=simple
Restart=always
ExecStart=/bin/bash /home/maxi/Desktop/start.sh
ExecStop=/bin/bash /home/maxi/Desktop/stop.sh
RestartSec=5
TimeoutSec=60
RuntimeMaxSec=infinity
PIDFile=/tmp/mydaemon.pid
[Install]
WantedBy=multi-user.target
Then:
sudo systemctl daemon-reload
sudo systemctl start myservice.service
sudo systemctl status myservice.service
Benefits of using such bash scripts is that you can handle some more things in this way. For example if you are using a virtual environment, you can use source activate in start.sh file before running the script.py .
Supervisord: Install Supervisor and create a supervisord.conf file for your script. A good guide is here:
https://csjourney.com/managing-processes-with-supervisor-in-depth-tutorial/
I found what was the problem. I used rc.local and started the program 10 seconds after boot. The system needed time first to set up before I could start the script.

Python script does not restart properly with systemd

I am learning how to restart a Python script in case of error (following this tutorial, however with some small tweaks regarding filenames and alike). First things first, the needed files:
/home/myuser/Desktop/test/test.py:
from datetime import datetime
from time import sleep
path = "/home/dec13666/Desktop/test/log.txt"
while True:
with open(path, "a") as f:
now = datetime.now().strftime("%d/%m/%Y %H:%M:%S")
f.write(now+"\n")
f.close()
sleep(1)
raise Exception("Error Simulation!!!")
davidcustom.service:
[Unit]
Description=Python Script Made By Me
After=multi-user.target
[Service]
RestartSec=10
Restart=always
ExecStart=python3 /home/myuser/Desktop/test/test.py
[Install]
WantedBy=multi-user.target
Finally, the commands run:
sudo nano /etc/systemd/system/davidcustom.service
sudo systemctl daemon-reload
sudo systemctl enable davidcustom.service
sudo systemctl start davidcustom.service
sudo systemctl status davidcustom.service
The message I am getting:
● davidcustom.service - Python Script Made By Me
Loaded: loaded (/etc/systemd/system/davidcustom.service; enabled; vendor preset: enabled)
Active: activating (auto-restart) (Result: exit-code) since Sun 2022-09-04 14:12:12 EDT; 8s ago
Process: 3341 ExecStart=python3 /home/myuser/Desktop/test/test.py (code=exited, status=1/FAILURE)
Main PID: 3341 (code=exited, status=1/FAILURE)
CPU: 100ms
Notes:
When I run test.py manually, it works OK, but then that python script is run from a service (as seen here), it generates that error.
I have tried to set User=myusername and Type=simple, in davidcustom.service ([Service]), with no difference in the results.
What am I doing wrong?
ExecStart requires an absolute path to the executable, it doesn't search $PATH. So use
ExecStart=/usr/bin/python3 /home/myuser/Desktop/test/test.py
(assuming that's where python3 is installed -- you can use type python3 to get the actual location).
I inadvertently added some wrong indentation in the original code (corrected by now in the original post). That solved my issue; when running sudo systemctl status davidcustom.service, now the service is active:
● davidcustom.service - Python Script Made By Dave
Loaded: loaded (/etc/systemd/system/davidcustom.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2022-09-04 16:16:02 EDT; 23ms ago
Main PID: 4287 (python3)
Tasks: 1 (limit: 14215)
Memory: 3.0M
CPU: 16ms
CGroup: /system.slice/davidcustom.service
└─4287 python3 /home/dec13666/Desktop/test/test.py
Other suggestions which would worth keeping in mind, but were NOT necessary for my case (thanks #Barmar & #tdelaney):
Use an absolute path at ExecStart (easily obtainable by running which python command)
If you only want to use your User and/or Group, then explicitely write those parameters.
The 2 previous suggestions should be added in [Service], in your service script:
[Service]
RestartSec=10
Restart=always
ExecStart=/usr/bin/python3 /home/myuser/Desktop/test/test.py
User=youruser
Group=yourgroup
Read the comments in the original post, for other options.
Thanks.

Can't get script to run from systemd or cron

I have a setup where I have a servercabinet with an external display that shows various system information. I only want it to turn on when I am present though, and I have made it soundactivated using SoundMeter https://github.com/shichao-an/soundmeter and a cheap USB microphone. When run manually everything works as it sohuld, but when i try to run it as a systemd service or a cronjob, it wont execute the second script that starts the display. From the logs I can see that Soundmeter works as it should, but it doesn't fire up the display.
Systemd service:
[Unit]
Description=Soundmeter
[Service]
Type=simple
Restart=always
#RestartSec=120
User=pi
ExecStart=/usr/local/bin/soundmeter -t +25 -a exec -e /opt/sysdroidUHHD/trigger.sh
[Install]
WantedBy=multi-user.target
Cronjob
#reboot /usr/local/bin/soundmeter -t +25 -a exec -e /opt/sysdroidUHHD/trigger.sh &
Contents of trigger.sh
#!/bin/bash
python3 /opt/sysdroidUHHD/sysdroid_main.py
exit 0
Any and all help is appreciated.
Remove that exit 0 from trigger.sh. Make sure your sysdroid_main.py starts some server or daemon that won't exit.

Systemd stucked into ExecStartPre step

I've made a very simple python program which extract the latests news popped in some website and send them to me via Telegram. The program is working perfectly when I am launching the command below in the console :
/usr/bin/python3.9 /home/dietpi/news/news.py
However when I try to automate it in systemd (to automatically restart if there is any bug or so), I noticed the services is blocked into the ExecStartPre step forever :
[Unit]
Description=News Service
Wants=network.target
After=network.target
[Service]
ExecStartPre=/bin/sleep 10
ExecStart=/usr/bin/python3.9 /home/dietpi/news/news.py
Restart=always
[Install]
WantedBy=multi-user.target
I put ExecStartPre command to let the Pi to setup properly the network before launching the program (I noticed a failure occur if not done, as the program starts too quickly and generates an error).
When I reboot the Pi, here is what I can see when I am opening the status of the services (by using the command: systemctl --type=service):
UNIT LOAD ACTIVE SUB JOB DESCRIPTION
news.service loaded activating start-pre start News Service
When I look more into detail on this service here is what I have (by using command: sudo systemctl status news.service):
● news.service - News Service
Loaded: loaded (/etc/systemd/system/news.service; enabled; vendor preset: enabled)
Active: activating (start-pre) since Fri 2022-02-04 17:03:58 GMT; 2s ago
Cntrl PID: 552 (sleep)
Tasks: 1 (limit: 4915)
CPU: 4ms
CGroup: /system.slice/news.service
└─552 /bin/sleep 10
Feb 04 17:03:58 DietPi systemd[1]: Starting News Service...
If I launch this command multiple time, I see the "activating" step goes up to 10s, then starts again from 0s >>> Which shows I am stuck in the ExecStartPre step :(
If you have any idea on how to solve this issue, it would be much appreciated :)
Try to create your own sleep script:
sleep.py:
import time
import sys
if __name__ == '__main__':
time.sleep(10)
sys.exit()
In your system unit:
ExecStartPre /usr/bin/python3.9 /home/dietpi/news/sleep.py
Personally, I prefer use supervisord to launch my python script as a service:
/etc/supervisor/conf.d/news.conf:
[program:news]
command = /usr/bin/python3.9 news.py
directory = /home/dietpi/news/
user = dietpi
autostart = true
autorestart = true
stdout_logfile = /var/log/supervisor/news.log
redirect_stderr = true

Why does systemd reap child process when running script with Fabric but not ssh?

I am running a Python script over SSH on an Ubuntu 18.04.2 server.
When I use ssh to login to the server and run the script, and then terminate the ssh session, the Python script also terminates as expected (I'm not using nohup, &, etc.) However, when I run the same script using Fabric, and then terminate the local Fabric process, the python process on the server gets reaped by systemd. This is what the systemd status looks like:
● session-219.scope - Session 219 of user root
Loaded: loaded (/run/systemd/transient/session-219.scope; transient)
Transient: yes
Active: active (abandoned) since Fri 2019-12-27 00:56:07 PST; 2min 55s ago
Tasks: 1
CGroup: /user.slice/user-0.slice/session-219.scope
└─6872 /root/peacock/bin/python3 -m src.main
Dec 27 00:56:07 master systemd[1]: Started Session 219 of user root.
Dec 27 00:57:52 master sshd[6783]: pam_unix(sshd:session): session closed for user root
Is there a way to prevent systemd from reaping the child process, similar to the behavior of ssh? And why does it only get reaped when using Fabric but not ssh directly?
More details:
The Python script is a simple flask app. The gist of it is:
flask_app = Flask('app')
#flask.route('/')
def index():
# ....
if __name__ == '__main__':
flask_app.run(host='0.0.0.0')
The Fabric script is roughly as follows:
server_conn = fabric.Connection('1.2.3.4')
with server_conn.cd('/root/peacock'):
server_conn.run('/root/peacock/bin/python3 -m src.main')
If you need to run a process as a daemon on the remote box, I would suggest that you make it a systemd unit. This way you can control it with standard commands and access its logs like any other service on the system.
Your config could look like (/etc/systemd/system/peacock.service):
[Unit]
Description=Peacock systemd service.
[Service]
Type=simple
ExecStart=/root/peacock/bin/python3 -m src.main
[Install]
WantedBy=multi-user.target
Remember to sudo chmod 644 /etc/systemd/system/peacock.service. Then your fabric script would look like:
server_conn = fabric.Connection('1.2.3.4')
with server_conn.cd('/root/peacock'):
server_conn.run('systemctl start peacock.service')
Later you can check status on this service. You will also be able to access logs with journalctl -u peacock

Categories

Resources