Mount units with Systemd


Image shamelessly borrowed from the Internet

Background

One of the first steps the end user must perform after installing ZoneMinder is to dedicate an entire partition, drive, or network share for ZoneMinder's event storage. The reason being, ZoneMinder will, by design, fill up your hard disk, and you don't want to do that to your root volume! The traditional method for accomplishing this is documented here, and that method continues to work well.

However, due to the mass adoption of Systemd we now have a new way to accomplish this, which happens to give us something the former method did not. Read on to learn more!

First, take a big sip from the Kool-Aid, and let the effects of Systemd wash upon you. See, that wasn't so bad, was it?

Systemd natively integrates all sorts of system admin functions that the legacy sys v init didn't have anything to do with. One of those functions is the ability to create mount points, much in the same way one would create a service (a.k.a. unit) file.

Collect Information

We need to know the following before we get started:
  • Find the ZoneMinder events and images folders on your filesystem
  • Determine the name of the web account user
  • For local volumes, determine the device name of the volume
  • For local volumes, determine the uuid of the volume
  • For remote volumes, determine the sharing protocol to be used e.g. nfs, smb, etc
  • For remote volumes, determine the share name

The location of the events and images folder will vary by Linux distro. You are looking for an actual folder, NOT a symlink! Redhat distros tend to put these folders under /var/lib/zoneminder while Debian distros prefer /var/cache/zoneminder. These folder locations are chosen by each distros' packaging guidelines.

On most Linux distros, you can view the uuid of each of your volumes like so:
ls -l /dev/disk/by-uuid
 On my system, the items above are as follows:
  • /var/lib/zoneminder
  • apache
  • /dev/sdb1
  • 6028c127-5d99-4860-981f-2984b4c10fd9
Your configuration will be different.

Migrate existing data

I'm not going to get into the details of this since the necessary steps will vary with each system. What you need to do is migrate whatever happens to be in the ZoneMinder events and images folders over to the new partition, disk, or network share. You do this by mounting the target from the command line via the normal fashion to a temporary folder, issue the appropriate move commands, and finally unmount the target.

Do that now.

Create the first Systemd Mount Unit

You will be creating a total of three mount units. The first mount unit mounts the drive or partition to your system. To do that create a new folder. I prefer to put mount points under /mnt and give the name of the subfolder the same name as the device or share. In my case, that would be sdb1.
sudo mkdir /mnt/sdb1
When creating mount units with systemd, the filename describing the mount point has to be named in a specific manner.  Since the folder I just created is at /mnt/sdb1, one has to name the mount unit mnt-sdb1.mount. Create that file in the /etc/systemd/system folder, then add the following contents, changing the path and uuid to match that of your system:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# systemd mount unit for ZoneMinder event storage
  
[Unit]
Description=systemd mount unit for ZoneMinder event storage
Before=zoneminder
  
[Mount]
What=/dev/disk/by-uuid/6028c127-5d99-4860-981f-2984b4c10fd9
Where=/mnt/sdb1
Type=ext4
Options=defaults,noatime,commit=120,data=writeback
  
[Install]
WantedBy=multi-user.target

Now enable and start the unit:
sudo systemctl enable mnt-sdb1.mount
sudo systemctl start mnt-sdb1.mount

Set Folder Permissions

We've created our primary mount point, but we aren't done yet. First, let's create some folders and set the correct permissions:
sudo su
mkdir -p /mnt/sdb1/zoneminder/events
mkdir -p /mnt/sdb1/zoneminder/images
chmod -R apache:apache /mnt/sdb1/zoneminder
exit
Remember that, if you are not running a Redhat distro, the web user account might be named something other than apache on your system.

Create two Systemd Bind Mount Units

With the events and images folders created, we want to create two mount units, which bind mount those folders into the desired places.

Create the file /etc/systemd/system/var-lib-zoneminder-events.mount then add the following content to it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# systemd bind mount unit for ZoneMinder event storage
 
[Unit]
Description=systemd bind mount unit for ZoneMinder event storage
After=mnt-sdb1.mount
Requires=mnt-sdb1.mount
 
[Mount]
What=/mnt/sdb1/zoneminder/events
Where=/var/lib/zoneminder/events
Type=none
Options=bind
 
[Install]
WantedBy=local-fs.target

Now enable and start the unit:
sudo systemctl enable  var-lib-zoneminder-events.mount
sudo systemctl start  var-lib-zoneminder-events.mount
We now need to do the same thing to the images folder. Create the file /etc/systemd/system/var-lib-zoneminder-images.mount then add the following content to it:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# systemd bind mount unit for ZoneMinder image storage
 
[Unit]
Description=systemd bind mount unit for ZoneMinder image storage
After=mnt-sdb1.mount
Requires=mnt-sdb1.mount
 
[Mount]
What=/mnt/sdb1/zoneminder/images
Where=/var/lib/zoneminder/images
Type=none
Options=bind
 
[Install]
WantedBy=local-fs.target

Now enable and start the unit:
sudo systemctl enable var-lib-zoneminder-images.mount
sudo systemctl start var-lib-zoneminder-images.mount
Now reboot and verify all three mount points were successful:
df -a
That's it!

Bonus Points. Leverage the Power of Systemd

If you recall, I mentioned that using systemd to manage your mount points has an advantage over the previous method. With your mount points configured with systemd, you can easily prevent ZoneMinder from starting, should the mount point fail for any reason. Anyone who has ever started ZoneMinder without realizing there was a problem reading from the events folder can tell you what happens when this occurs. You lose all your events, and yes this is by design.

To prevent that from happening we need to modify our zoneminder service file. First, make a copy of it:
sudo cp /usr/lib/systemd/system/zoneminder.service /etc/systemd/system/
Then open the copy and add "Requires=mnt-sdb1.mount" under the [unit] block:

1
2
3
4
5
6
7
8
# ZoneMinder systemd unit file for CentOS 7
 
[Unit]
Description=ZoneMinder CCTV recording and security system
After=network.target mariadb.service httpd.service
After=zfs.target zfs-mount.service zfs-share.service
Requires=mariadb.service httpd.service
Requires=mnt-sdb1.mount

Now issue a daemon reload to tell systemd to pick up the change:
sudo systemctl daemon-reload
Should the mount point fail during startup, systemd will prevent the ZoneMinder service from starting with a message stating a failed dependency. Your events are saved from deletion!