Monitoring a Directory with Systemd
John L. Carveth
I've been using Linux as my daily driver OS for a couple of years now, but it's only recently that I started using Linux everyday as a part of my job. A lot of those days, I find myself using systemd
. It's wonderful. I can manage software deployments, schedule tasks, listen to network sockets, and as the title of this article suggests I can use systemd to monitor a certain path for changes.
The server is running a small piece of reporting software, which listens for HTTP requests and generates reports in an HTML format. These .html
files are written to the server once they are generated. I wanted a script to execute each time a new report was written to that directory in order to convert that html into a .pdf
and subsequently print the file. There are a few pieces involved in getting a workflow like this to work. This article will only cover using systemd to monitor for changes.
We'll start by writing the shell script we want systemd to execute.
#!/bin/sh
WORKING_DIR=/opt/spinv-backend/reports
REPORT_FILES=$WORKING_DIR/*.html
for file in $REPORT_FILES;
do
filename=$(basename -- "$file");
filename="${filename%.*}"
printf "Converting $filename to $filename.pdf\n";
# Convert .html file to .pdf
wkhtmltopdf $file $WORKING_DIR/pdf/$filename.pdf
# Send .pdf to print queue
printf "Sending $filename.pdf to print queue...\n"
lp $WORKING_DIR/pdf/$filename.pdf
# Move .html file to archive so not printed twice
mv $file $WORKING_DIR/archive/
printf "$file done\n"
done;
Fairly straight-forward, this script loops through the /opt/spinv-backend/reports
directory over any file ending in .html
. This file is then converted and sent to the print queue using wkhtmltopdf
and CUPS
respectively.
How, we need a service file (let's call it report.service
) that runs this script:
[Unit]
Description=Converts and prints spire-inventory reports.
[Service]
Type=OneShot
ExecStart=/opt/spinv-backend/printReports.sh
[Install]
WantedBy=multi-user.target
That's all that's needed for the base service. We still need another service unit that monitors the path. It will have the same name as the service file we just created, only with a .path
extension instead of .service
:
[Unit]
Description=Monitor /opt/spinv-backend/reports for changes.
[Path]
PathChanged=/opt/spinv-backend/reports/
Unit=report.service
[Install]
WantedBy=multi-user.target
Now that we have the necessary service files, all that's left is symlinking our service files to /etc/systemd/system
and then start them.
sudo ln -s /opt/spinv-backend/report.service /etc/systemd/system/report.service
sudo ln -s /opt/spinv-backend/report.path /etc/systemd/system/report.path
sudo systemctl enable report.{path,service}
sudo systemctl start report.path
That's it!