I found several solutions on the internet for monitoring the CIFS/NFS mounts that are mapped from remote hosts, unfortunately, I found them too aggressive in combination with Zabbix and decided to write a new type of implementation by myself.

When talking about scripting, we need something that will be very dynamic in terms, if we add more components to our system, in this case, mounts – they should be affected as well by the scope of our code, it should be robust and stable, meaning – no false positives and no false negatives(we can always switch positive/negative logic).

Below is the code of the Bash script that I made for this purpose and the description is quite simple, the script will find and parse all of the mounts from ‘/etc/fstab’ that contain CIFS or NFS parameter and take source and destination into arrays, after it will loop over the arrays and try to output(touch) the file three times, with the timeout of 5 seconds in interval of 1 second in between, in case it fails to touch the file two or more times, it will report a problem, also it will report a problem in case the mount is not mounted at all.

 #!/bin/bash
SOURCE=($(cat /etc/fstab | egrep 'cifs|nfs' | awk '{ print $1 }'))
DESTINATION=($(cat /etc/fstab | egrep 'cifs|nfs' | awk '{ print $2 }'))
FILENAME="mounttest.txt"
for ((i = 0; i < ${#SOURCE[@]}; i++)); do
TEST=$(findmnt -S "${SOURCE[$i]}" -T "${DESTINATION[$i]}" | awk '{ print $2 }' | grep -iv source)
if [ -z $TEST ]; then
echo "Mount pointing to ${DESTINATION[$i]} is not mounted"
else
n=0
RESULT=0
until [ $n -ge 3 ];do
timeout -s 15 5 touch "${DESTINATION[$i]}/${FILENAME}" > /dev/null 2>&1
if [ $? -ne 0 ]; then
RESULT=$((RESULT+1))
fi
n=$[$n+1]
sleep 1
done
if [ $RESULT -ge 2 ]; then
echo "There is a connectivity issue with ${SOURCE[$i]}"
fi
fi
done 

Now it comes to Zabbix part, we are supposed to deploy the script to all of our servers where we want Zabbix agent to execute it, we also have to create a “UserParameter” file that will instruct Zabbix where to find the script and how to execute it. My preference is to deploy this via Ansible – since it is the fastest way and configuration management tool that we use in-house.

The layout of “UserParameter” file looks like this.

UserParameter=check.mount[*],/usr/sbin/check_mount.sh

I will now present a layout of Ansible role, but since this is not the Ansible class, I will post just a part of it

---
- name: Copy over custom userparameter files
  copy:
    src: "{{ item }}"
    dest: "/etc/zabbix/zabbix_agentd.d/{{ item | basename }}"
    owner: root
    group: root
    mode: 0644
  notify: restart zabbix-agent
  with_fileglob:
    - files/custom-userparameters/*.conf

- name: Configure sudoers to allow zabbix to touch as root
  lineinfile:
    path: /etc/sudoers
    line: "zabbix ALL=(ALL) NOPASSWD: /usr/bin/touch, /usr/bin/timeout"
    state: present
    validate: 'visudo -cf %s'

- name: Copy over the check mount script
  copy:
    src: check_mount.sh
    dest: /usr/sbin/check_mount.sh
    mode: 0755
  notify: restart zabbix-agent

We are keeping in mind that SELinux is enabled on our servers, so we have to explicitly allow the agent to use some system utilities as a Root.

Once we have deployed script and “UserParameter” file to our servers, let’s configure item and trigger in our custom Zabbix template.

We are proceeding with Item creation, we are using active checks in order to offload actions to our agents, instead of overloading our server, the item is configured as on picture below.

Screenshot_6

Now trigger comes in place, in case it receives the string which length is greater than zero=0, it will send us alert that will contain a description of the item, in this case, the output of our script, example – There is a connectivity issue with ${SOURCE[$i}, for the purpose of delivering messages, we use custom Telegram API.

Screenshot_7