How to create a systemd file exchange service

How to create a systemd file exchange service

We are going to explore how basic Linux utility functions like curl, logger and inotifywait will allow us to define a basic file exchange service

In this article, we are going to go over an example for defining a systemd service that will allow the user to exchange files with another machine. It will work by specifying a couple of folders for sending and receiving files. These files will be exchanged using the File Transfer Protocol, commonly known as FTP, which is a standard network protocol used for transferring files from one host to another over a TCP-based network, such as the Internet. An FTP service serves as an intermediary platform that facilitates the seamless movement of files, providing a reliable and structured way to exchange data.

Installation

The first step will consist of installing the dependencies required for executing the service. These will be curl for sending the file using FTP, and pure-ftpd as FTP server.

sudo apt install curl
sudo apt install pure-ftpd
sudo apt install inotify-tools

Send service

The send service will consist of a send.sh script, which takes five arguments:

  • out_tray: this is the folder where the user has to put the files to be sent to the destination host.

  • ftp_user: user used for the FTP connection.

  • ftp_password: password for the user of the FTP connection.

  • ftp_host: destination host for the FTP transfer.

  • ftp_folder: folder within the destination host where the files are going to be copied.

This script monitors the out_tray folder checking for new files using the inotifywait utility. Once a new file is detected, it sends the file to the FTP destination using curl. It also uses the logger utility to print traces about the execution of the script.

#!/bin/bash
if [ $# -ne 5 ]; then
  echo "Usage: send.sh <out_tray> <ftp_user> <ftp_password> <ftp_ip> <ftp_folder>";
  exit;
fi

while file="$(inotifywait -q -e move --format %f $1)";
do
  logger "[`basename "$0"`] Sending file $file"
  curl -T $1/$file ftp://$4/$5/$file --user $2:$3
  rm $1/$file;
  logger "[`basename "$0"`] Sent file $file"
done

The next step is to define a systemd service that will call the send.sh script.

[Unit]
Description=Send Service

[Service]
ExecStart=/usr/local/bin/transferor/send.sh /usr/local/bin/transferor/outTray al al 127.0.0.1 /usr/local/bin/transferor/inTray
StandardOutput=null
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=send.service

Receive service

The receiving service will follow a similar approach. It will be composed of the recv.sh script, which takes two arguments:

  • in_tray: folder where files sent through FTP from the source host are received.

  • script: script file to be executed to process the files received in the in_tray folder.

This script also monitors a folder using the inotifywait utility. Once a new file appears in the in_tray folder, it runs the script specified as an argument to process the received file. As the send.sh did, it uses the logger utility to print traces about the execution of the script.

#!/bin/bash
if [ $# -ne 2 ]; then
  echo "Usage: recv.sh <in_tray> <script>";
  exit;
fi

while file="$(inotifywait -q -e close_write --format %f $1)";
do
  logger "[`basename "$0"`] Received file $file"
  source $2 "$1/$file";
  logger "[`basename "$0"`] Processed file $file"
done

For example, we can define an echo.sh processing script that just echoes the content of the received file.

#!/bin/bash

cat $1

After coding these two scripts, we can define the systemd service that will execute the recv.sh script.

[Unit]
Description=Receive Service

[Service]
ExecStart=/usr/local/bin/transferor/recv.sh /usr/local/bin/transferor/inTray /usr/local/bin/transferor/echo.sh
StandardOutput=null
Restart=on-failure

[Install]
WantedBy=multi-user.target
Alias=recv.service

Deployment

Once we have all the scripts and services defined, we can deploy them to the proper folders and set them up to be run as systemd services.

#!/bin/bash

TARGET=/usr/local/bin/transferor

echo "Creating directory $TARGET"

sudo mkdir $TARGET
sudo mkdir $TARGET/inTray
sudo chown al:al $TARGET/inTray
sudo mkdir $TARGET/outTray
sudo chown al:al $TARGET/outTray

echo "Copying files into $TARGET"
sudo cp app/echo.sh $TARGET
sudo cp recv/recv.sh $TARGET
sudo cp recv/recv.service $TARGET
sudo cp send/send.sh $TARGET
sudo cp send/send.service $TARGET

echo "Installing services"
sudo ln -s $TARGET/recv.service /etc/systemd/system
sudo systemctl enable recv
sudo ln -s $TARGET/send.service /etc/systemd/system
sudo systemctl enable send

echo "Done"

After deploying the scripts and services, we have to reboot the machine. And after that, we can check the status of the defined services.

sudo reboot
sudo systemctl status recv
sudo systemctl status send

Testing the example

At this point, we should have both services up and running. Therefore, we can do a quick test to check that they work as expected. To do so, we just have to copy a test file into the out_tray folder, and we will see the content of that file in the log messages of the logger utility.

echo "test" > test.txt
sudo mv test.txt /usr/local/bin/transferor/outTray

journalctl -f

Conclusion

In this article, we have seen a simple way of defining a systemd service that allows you to easily send files between hosts, just by copying them to the outbound folder. And allows you to run a script to process the received file in the destination host. That way you could automate the distribution and processing of files among multiple machines. Obviously, this example is not suitable for production code. But it allows you to get a grasp of how basic utilities like inotifywait, logger, curl and the definition of systemd services work.