How to start systemd service after NFS mount in Linux


systemd, Linux, NFS

How to execute a script after a network file system is mounted? How to start a systemd service only after NFS share is mounted and available in Linux? Is it possible to execute a script via systemd service after network share such as NFS, CIFS is mounted in Linux? How to check if a device is mounted with systemd?

I have been getting these questions quite often from different users now. With the introduction of systemd in RHEL/CentOS 7 now we have much more control over how system services, mount points are handled and managed. Although it is possible that the amount of configuration options can be overwhelming even for an advanced users for certain scenarios. Since we have so many options to choose from, we tend to get confuse to choose the best possible option which suffice our requirement.

In this tutorial I will share the systemd dependencies required to check if a network share such as NFS/CIFS is mounted before starting the service.

 

1. Create Network Share

For the sake of demonstration I will use an NFS share. I have already written a well detailed article on steps to configure NFS server so I will not repeat the same. Let me quickly setup my NFS server with a single share with read write permission.

[root@nfs-server ~]# exportfs -v
/data           (sync,wdelay,hide,no_subtree_check,sec=sys,rw,no_root_squash,no_all_squash)

 

2. Create systemd unit to mount NFS share

Let's move on to the NFS Client. Since I am using RHEL/CentOS, I will install nfs-utils on the server to access NFS share. For other distributions and more details to mount NFS share you should read: Beginners guide to mount NFS share in Linux with examples

 

Before I create a systemd unit file, let me try to mount the NFS share manually to make sure the configuration is proper

[root@nfs-client ~]# mount 192.168.43.10:/data /share

[root@nfs-client ~]# df -h /share/
Filesystem           Size  Used Avail Use% Mounted on
192.168.43.10:/data   17G  2.2G   14G  14% /share

So our share from the NFS server is properly accessible. Let's unmount it as we will mount it using systemd mount unit file.

[root@nfs-client ~]# umount /share/

Below is my systemd unit file for mounting the NFS share

[root@nfs-client ~]# cat /etc/systemd/system/share.mount
[Unit]
Description=NFS Share from nfs-server.example.com(192.168.43.10)
DefaultDependencies=no
Conflicts=umount.target
After=network-online.target remote-fs.target
Before=umount.target

[Mount]
What=192.168.43.10:/data
Where=/share
Type=nfs
Options=defaults

[Install]
WantedBy=multi-user.target

Let's understand the [Unit] section:

  • target units will complement all configured dependencies of type Wants= or Requires= with dependencies of type After= unless DefaultDependencies=no is set in the specified units.
  • We put umount.target with Conflicts= to make sure that the conflicting unit is stopped before the other unit is started
  • Since NFS is dependent on network we put network-online.target and remote-fs.target under After=.
  • The netfs(remote-fs.target) service is responsible for mounting the network-related file systems listed in /etc/fstab (NFS, SMBFS/CIFS, NCP, or any line with _netdev option).
  • It will only mount these types of filesystems once the system starts the network. If this service is not started at boot time, the network-related file systems will not be mounted.
  • Also we would like to call our service before umount.target

In think the [Mount] section is pretty much self-explanatory so let's skip the remaining section. If you are still interested to learn about mount unit files then I have written another detailed article on this topic with different examples.

 

Reload the systemd changes. This is an important step, do not skip this:

[root@nfs-client ~]# systemctl daemon-reload

Let's verify this mount unit service file to make sure it mounts the NFS share

[root@nfs-client ~]# systemctl start share.mount

Check the status of this service

[root@nfs-client ~]# systemctl status share.mount
● share.mount - NFS Share from nfs-server.example.com(192.168.43.10)
   Loaded: loaded (/etc/systemd/system/share.mount; enabled-runtime; vendor preset: disabled)
   Active: active (mounted) since Sun 2020-08-30 10:40:42 IST; 1s ago
    Where: /share
     What: 192.168.43.10:/data
    Tasks: 0 (limit: 30445)
   Memory: 156.0K
   CGroup: /system.slice/share.mount

Aug 30 10:40:42 nfs-client.example.com systemd[1]: Mounting NFS Share from nfs-server.example.com(192.168.43.10)...
Aug 30 10:40:42 nfs-client.example.com systemd[1]: Mounted NFS Share from nfs-server.example.com(192.168.43.10).

Verify if the share is mounted on the mount point

[root@nfs-client ~]# df -h /share/
Filesystem           Size  Used Avail Use% Mounted on
192.168.43.10:/data   17G  2.2G   14G  14% /share

Since everything looks good we will enable the service or else this will not be executed at reboot stage.

[root@nfs-client ~]# systemctl enable share.mount
Created symlink /etc/systemd/system/multi-user.target.wants/share.mount → /etc/systemd/system/share.mount.

Post reboot of the node my share is properly mounted:

[root@nfs-client ~]# df -h /share/
Filesystem           Size  Used Avail Use% Mounted on
192.168.43.10:/data   17G  2.2G   14G  14% /share
NOTE:
Instead of using systemd unit file to mount NFS share you can use the legacy method i.e. /etc/fstab to mount the NFS share during reboot. The fstab will also internally create the systemd unit file to mount the NFS share. Go ahead and add below content
# NFS_SERVER:/PATH/TO/EXPORTED/DIR    /MOUNT_POINT_ON_CLIENT    TYPE_OF_FS   OPTIONS   DUMP	PASS
  192.168.43.10:/data                 /share                    nfs          defaults    0    0

 

Create script (Optional)

I assume you already have your script which you wish to execute after mounting the NFS share. But for the sake of demonstration I will create a small shell script. I will execute the script as root user but you can also configure it to be called as a certain user instead of root.

This script will perform certain pre-checks and then create a directory under /share.

#!/bin/bash

NFS="/share"
SCRIPT_NAME=$(basename $0)
log=`echo /tmp/${SCRIPT_NAME%%.*}.log`
echo "Log File Name: $log"

echo "Starting at `date`" | tee -a $log
echo "Check if our share is mounted already"
mount | grep $NFS >> $log

echo "DEBUG: List mount unit files at the stage when script is called during reboot"
systemctl list-units --all --type=mount >> $log

if `mount | grep -q "$NFS"`; then
    echo "$NFS found" | tee -a $log
else
    echo "$NFS dir not available" | tee -a $log
fi

# start our console log
outdir="$NFS/dir_$(date +%d-%m-%Y-%T)"
echo "Creating directory $outdir" | tee -a $log
mkdir -p $outdir
rc=$?
echo "rc from mkdir: $rc" | tee -a $log
if [[ ! -d "$outdir" ]]; then
    echo "Something is wrong, $outdir does not exist" | tee -a $log
    exit 7
fi    

 

Create systemd service unit file to execute script after NFS mount

This is main part of this tutorial.

We will cover the dependencies required in the systemd unit file to execute a script after our device is mounted and available.
I prefer to create the service unit file inside /etc/systemd/system instead of other location

# cat /etc/systemd/system/nfs-share.service
[Unit]
Description="Execute script after NFS share is mounted"
RequiresMountsFor=/share

[Service]
Type=simple
RemainAfterExit=yes
ExecStart=/root/create_dir.sh

[Install]
WantedBy=default.target

We have used RequiresMountsFor to make sure the provided mount point is in use. This automatically adds dependencies of type Requires= and After= for all mount units required to access the specified path.

Let's start the service and verify if it is working

[root@nfs-client ~]# systemctl start nfs-share.service

Check the status of the service

[root@nfs-client ~]# systemctl status nfs-share.service

 

 

Now if you check the property of this unit file, it will automatically add Requires= and After= section with the provided mount point.

[root@nfs-client ~]# systemctl show nfs-share.service | grep -E 'After=|Requires='
Requires=share.mount sysinit.target -.mount system.slice
After=systemd-journald.socket basic.target share.mount sysinit.target -.mount system.slice

So the service has properly started and has already created the directory on the NFS share as expected

[root@nfs-client ~]# ls -l /share/
total 4
drwxr-xr-x 2 root root 4096 Aug 30 11:32 dir_30-08-2020-11:32:19

Next enable the service to make sure it starts automatically after reboot

[root@nfs-client ~]# systemctl enable nfs-share.service
Created symlink /etc/systemd/system/default.target.wants/nfs-share.service → /etc/systemd/system/nfs-share.service.

 

Next reboot the server and verify if it works:

[root@nfs-client ~]# ls -l /share/
total 8
drwxr-xr-x 2 root root 4096 Aug 30 11:32 dir_30-08-2020-11:32:19
drwxr-xr-x 2 root root 4096 Aug 30 11:36 dir_30-08-2020-11:36:08

So post reboot I have one more directory under the /share folder so life is good.

 

This was a very basic example, you may have a script which would require to run for a longer period of time in such case you can use TimeoutStartSec to define the time period for which the service should wait before killing the script and marking the systemd service as failed.

But be aware that TimeoutStartSec cannot be used with Type=oneshot as with this TimeoutStartSec is disabled by default.

 

Conclusion

In this tutorial we covered the steps to execute a systemd service after a network device is mounted. This network device can be anything such as NFS, CIFS, SMBFS etc as long as these network shares are mounted locally using systemd the same can be used as a dependency to execute other dependent services. But what if you don't have a control on how these network shares are mounted? We will cover that in our next article.

 

What's Next

It is possible you don't have a control on how these network shares are mounted? For example a shared folder from Oracle VirtualBox which is mounted by the VirtualBox itself using vboxsf kernel module. In such case RequiresMountsFor will not work. Let's see how we can access a network share mounted by VirtualBox shared folder.

How to access VirtualBox shared folder at startup with systemd in Linux

 

Deepak Prasad

Deepak Prasad

He is the founder of GoLinuxCloud and brings over a decade of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels in various domains, from development to DevOps, Networking, and Security, ensuring robust and efficient solutions for diverse projects. You can connect with him on his LinkedIn profile.

Can't find what you're searching for? Let us assist you.

Enter your query below, and we'll provide instant results tailored to your needs.

If my articles on GoLinuxCloud has helped you, kindly consider buying me a coffee as a token of appreciation.

Buy GoLinuxCloud a Coffee

For any other feedbacks or questions you can send mail to admin@golinuxcloud.com

Thank You for your support!!

Leave a Comment