I have a Python script that I would like to run automatically on boot, that is, it executes in the background on boot.
I found the following short dessciption where you have to fill in the <…> fields of course.
Create a file with name <name>.service in /etc/systemd/system with contents
[Unit]
Description=<short description>
[Service]
Type=forking
ExecStart=<absolute path to your program/script>
[Install]
WantedBy=multi-user.target
The <aboslute path to your program/script> could be something like /usr/local/bin/.
And of course after copying your program/script there, do not for get to allow execute permission for at least the owner root.
Then, to start it at following boots:
systemctl enable <name>.service
And to start it now:
systemctl start <name>.service
And to check the service’s status:
systemctl status <name>.service
This depends on how daemon is implemented. Defining wrong type will simply result in failure to start service.
I don’t quite get what you mean here. A little more info would do.
I get
Job for imon.service failed. See "systemctl status imon.service" a
nd "journalctl -xn" for details.
after some time.
(the filename is imon.service)
I did not actually enable the service using
sudo systemctl enable imon.service
I just started the service first in order to check it and see if it’s working before I restart PC.
Well, there are two suggestions there. Did you do them? And when yes, why not postingthe results? And when no, why not?
That is alright. You understand that correct.
As I tried t o explain in my post: I found this somewhere. It is just a starting point for the OP.
Trying to understand more of systemd is of course very useful. Start at
man systemd
But the amount of information is huge
The [Service] section is in
man systemd.service
and there it says:
Type=
Configures the process start-up type for this service unit. One of simple, forking, oneshot, dbus, notify or idle.
If set to simple (the default value if neither Type= nor BusName= are specified), it is expected that the process configured with ExecStart= is the main process of the service. In this mode, if the process offers functionality to other processes on the system, its communication channels should be installed before the daemon is started up (e.g. sockets set up by systemd, via socket activation), as systemd will immediately proceed starting follow-up units.
If set to forking, it is expected that the process configured with ExecStart= will call fork() as part of its start-up. The parent process is expected to exit when start-up is complete and all communication channels are set up. The child continues to run as the main daemon process. This is the behavior of traditional UNIX daemons. If this setting is used, it is recommended to also use the PIDFile= option, so that systemd can identify the main process of the daemon. systemd will proceed with starting follow-up units as soon as the parent process exits.
Behavior of oneshot is similar to simple; however, it is expected that the process has to exit before systemd starts follow-up units. RemainAfterExit= is particularly useful for this type of service.
Behavior of dbus is similar to simple; however, it is expected that the daemon acquires a name on the D-Bus bus, as configured by BusName=. systemd will proceed with starting follow-up units after the D-Bus bus name has been acquired. Service units with this option configured implicitly gain dependencies on the dbus.socket unit. This type is the default if BusName= is specified.
Behavior of notify is similar to simple; however, it is expected that the daemon sends a notification message via sd_notify(3) or an equivalent call when it has finished starting up. systemd will proceed with starting follow-up units after this notification message has been sent. If this option is used, NotifyAccess= (see below) should be set to open access to the notification socket provided by systemd. If NotifyAccess= is not set, it will be implicitly set to main. Note that currently Type=notify will not work if used in combination with PrivateNetwork=yes.
Behavior of idle is very similar to simple; however, actual execution of the service binary is delayed until all jobs are dispatched. This may be used to avoid interleaving of output of shell services with the status output on the console.
As there is no information about what the deamon should do (the only information we have is the language in which it is written, which is not very important), I will not suggest what type to use.
I was about to post the results before I saw this post [SOLVED] Help with systemd .service script / Programming & Scripting / Arch Linux Forums. So I modified the file imon*.service *and removed the line
Type=forking
Then I started the service. This time the service ran without error. However, the script does not do what I expect it to.
This means that I explain what the Python does. First, the script is headless. It monitors the USB connections and, when a mobile phone device is tethered, it initiates some code which scrapes my ISPs website for some data. It then sends a notification using the scraped data.
This is the code:
#! /usr/bin/python
import glib
import re
import subprocess
import requests
import bs4
import datetime
import sys
import os
from selenium import webdriver
from pyudev import Context, Monitor
from selenium.common.exceptions import NoSuchElementException
def get_network_data(tout):
"""Scrapes balance data from ISP website."""
if tout is not None:
driver = webdriver.PhantomJS()
driver.set_window_size(1120, 550)
driver.get('http://mydata.myisp.com')
try:
acc = driver.find_element_by_id('account')
tbody = acc.find_element_by_tag_name('tbody')
match_obj = re.findall(r'(\w\s]+)\:\s(\d\s\.\-]+\w]{0,3})\s
](\w\s]+)\:\s(\d\s\.\-]+\w]{0,3})\s
]', tbody.text)
if match_obj is not None:
data = {}
for item in match_obj:
data.update(dict(zip(*[iter(item)]*2)))
expiry_date = datetime.datetime.strptime(data'Expire Date'], '%Y-%m-%d')
remaining = expiry_date - datetime.datetime.now()
bundle_balance = 'Bundle balance: {0} - {1} day(s) remaining'.format(data'Bundle Balance'], remaining.days)
airtime_balance = 'Airtime balance: %s' % data'Current Airtime Balance']
time_now = datetime.datetime.now().strftime('%H:%-M %Y/%m/%d')
imon = open(os.path.join(os.path.expanduser('~/Developer/2theboringstuff'), 'imonitor.txt'), 'a+')
write_string = time_now + '
' + bundle_balance + '
' + airtime_balance + '
'
imon.write(write_string)
imon.close()
subprocess.call('notify-send', 'Orange Balance', '
{0}
{1}'.format(bundle_balance.capitalize(), airtime_balance.capitalize())])
else:
subprocess.call('notify-send', 'Orange Balance', '
{0}'.format('Error: Could not retrieve data from page.')])
except NoSuchElementException:
subprocess.call('notify-send', 'iMonitor:get_network_data', '
{0}'.format('Error: Could not locate element - acc.')])
else:
subprocess.call('notify-send', 'iMonitor', '
{0}'.format('Error: Could not find USB device.')])
def identify_phone(observer, device):
"""Identifies if specific USB device (phone) is connected (tethered)."""
global last_updated, initial_search, msg_count
current_time = datetime.datetime.now()
time_diff = current_time - last_updated
if (time_diff.seconds > 300) or initial_search:
try:
tout = subprocess.check_output("lsusb | grep 1234:5678", shell=True)
except subprocess.CalledProcessError:
tout = None
last_updated = datetime.datetime.now()
initial_search = False
get_network_data(tout)
if not initial_search and msg_count == 1:
wait_time = datetime.datetime.fromtimestamp(600 - time_diff.seconds)
message = wait_time.strftime('You may have to wait %-M minute(s), %-S second(s) before another check is done.')
subprocess.call('notify-send', 'iMonitor:identify_phone', '
{0}'.format(message)])
msg_count += 1
if time_diff.seconds > 10:
msg_count = 1
try:
initial_search = True
last_updated = datetime.datetime.now()
msg_count = 1
try:
from pyudev.glib import MonitorObserver
except ImportError:
from pyudev.glib import GUDevMonitorObserver as MonitorObserver
context = Context()
monitor = Monitor.from_netlink(context)
monitor.filter_by(subsystem='usb')
observer = MonitorObserver(monitor)
observer.connect('device-added', identify_phone)
monitor.start()
glib.MainLoop().run()
except KeyboardInterrupt:
print('
Shutdown requested.
Exiting gracefully...')
sys.exit(0)
when I ran this script normally in the terminal as
./imonitor.py
, it works but using the service I do not get any output.
Where do you expect output to go??? Services start under root
As you can see, from the script, I should get a notification. So, I added some lines that would write to the file imonitor.txt. The file writing works but the notification does not.
So is root getting notified??
I don’t read python
But you must consider the environment at the point that any script runs and what resources are running at that point. Maybe start it when a user logs in not at system start
You are constantly talking about when I run and I get a notification. I understand very vaguely what you mean, but you should be precise. “I” is not a concept of Linux. Liinux only knows users. Thus you must talk which user does what and gets what and in what way.
When a normal end-user runs the program in a terminal and gets output, and that is OK, then what do you think that happens when the same process is running “in the background” (as you specified that it should) and thus has no terminal connected to it. Where is the output going and where is that “notification” going? And what do you mean with “notification”? A red light that starts blinking?
I am not sure how to put the conversation but lemme give it a try.
Say, am logged in as user==giantas. When giantas does
./imonitor.py
there is some scraping then a desktop notification appears. So, I expect that when root runs the headless script, giantas would get a desktop notification.
I hope that explains
Why?
- It is not sure that a desktop session is running at all. Where should the notification go?
- If there is a desktop running by giantas, why would the script, running as root, decide it would be a nice idea to pester giantas? Nowhere in your script user giantas is mentioned as being a special user that should be notified.
- There can be many desktop sessions (plural) running at the same time, for giantas and for other users. Again where does your scriipt decide on which session it should notify. Or should it notify on all of them?
- The script is running with root as owner, thus you might conclude that a notification of some form (opening wwindow with some text?) might be done on a GUI session run by root. But there won’t be one were it only because it is very stupid to run a desktop session as root.
All these thoughts and combinations of them should already have convinced you that it is not obvious for a background running process to create the sort of notification you are tying to achieve.
So, what’s your point? I don’t get you.
I think suggestions (with explanations) would do better than questions. Don’t you think? Because up to now am still waiting for help and since I have already posted my script you have an option of saying you know how to help or you don’t. Simple.
Sorry that I can’t make myself clear.
What I try to do is to show you how you yourself could have concluded that a background process running as root will not be able to open window on a not identified (and possibly not even existing) GUI session.
I try to make you understand that while a program run from a GUI session of user giantas may be able to open window on that same GUI session, this will not be the case when the same program is run by root in the background.
This because you seem not to see the basic flaw in your strain of thoughts.
I might add, that your original question on how to start a program on boot is answered.
Now you have a complete different question: how to open a window on one or more existing or not existing GUI sessions from a background program. IMHO that is something that should go into the Development > Programming/Scripting section of these forums.
Linux is multi user. Also Linux does not require a GUI at all. As we try to tell you it is all about the environment at the time the script is run. Running it at system start up only root is logged in and there is NO GUI at all running. So where exactly does the notification go??? Not anywhere you can see it. Where should it go which user at what time??
In Windows the GUI is part of the OS. In Linux it is not it is just another program.
In Windows the line between Administrator and user is blurred, In Linux root is not the same as a normal user and the lines are sharply drawn