Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

Shell hack: docker-nfs-check

I use docker containers that mount nfs mounts. Sometimes if the docker server comes up before the nfs server does, (and the systemd service dependency definitions don't work), then I want to bounce the services after I've gotten nfs working.

This affects things like my photo app (PhotoPrism) and metube which store files on the network share.

#!/bin/sh
# Startdate: 2023-07-18-3 11:00
# File: /usr/local/bin/docker-nfs-check
# Purpose: check nfs
# Usage:
#    must define DOCKER_SERVICE to run this. It loads /etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE} file to load the rest of the env vars
LOGFILE=/mnt/public/Support/Systems/server4/var/log/docker-nfs-check/log
exec 3>&1
{
   {
      {
         # initial loading of values
         test -z "${DOCKER_SERVICE}" && test -n "${1}" && DOCKER_SERVICE="${1}"
         test -z "${DOCKER_SERVICE}" && { printf '%s\n' "Fatal: need DOCKER_SERVICE set to a docker service to load env vars from /etc/sysconfig/docker-nfs-check/\${DOCKER_SERVICE} file." 1>&2 ; exit 1 ; }
         if ! test -f "/etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}" ;
         then
            printf '%s\n' "Fatal: no file found for /etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}. Aborted." 1>&2
            exit 1
         fi
         . "/etc/sysconfig/docker-nfs-check/${DOCKER_SERVICE}"
         for word in DS_LINES DS_PATH DS_CONTAINER DS_USER DS_SERVICE ;
         do
            _var="$( eval "echo \$${word}" )"
            test -z "${_var}" && { printf '%s\n' "Fatal: need ${word} defined. Aborted." 1>&2 ; exit 1 ; }
         done
         # main
         output="$( sudo su - "${DS_USER}" -s /bin/bash -c "cd ${DS_PATH} ; docker-compose exec ${DS_CONTAINER} mount | awk \"\\\$5~/nfs/{print \\\$1,\\\$3}\" ;" )"
         # output should be ${DS_LINES} lines:
         # server3:/var/server3/shares/public/Images/photoprism-imported /photoprism/originals
         # server3:/var/server3/shares/public/Images/photos /photoprism/originals/photos
         if test "$( echo "${output}" | wc -l )" != "${DS_LINES}" ;
         then
            printf '%s\n' "restarting which is missing the nfs mounts."
            sudo systemctl restart "${DS_SERVICE}"
         else
            printf '%s\n' "All good:"
            printf '%s\n' "${output}"
         fi
      } 2>&1 1>&3 | sed -r -e "s/^/STDERR: /;"
   } 3>&1 2>&1
} | plecho ${DOCKER_SERVICE} | tee -a "${LOGFILE}"

It uses my favorite shell redirection spaghetti boilerplate code to prepend STDERR to standard error messages that all end up in the same place.

But inside all that, is the sauce of running the "mount" command and then restarting the docker container if the output is not as expected.

I use shell completion:

# File: /etc/bash_completion.d/docker-nfs-check
# vim: set syntax=sh:
# startdate: 2023-07-18-3 15:45
_docker_nfs_check() {
   local cur prev words cword;
   _init_completion || return
   _tmpfile1="$( mktemp )"
   # populate list
   find /etc/sysconfig/docker-nfs-check  -mindepth 1 -maxdepth 1 ! -type d ! -name '.*' -printf '%P\n' > "${_tmpfile1}"
   COMPREPLY=($( compgen -W "$( cat ${_tmpfile1} )" -- "$cur" ))
   command rm -rf "${_tmpfile1:-NOTHINGTODEL}" 1>/dev/null 2>&1
   return 0
} &&
complete -F _docker_nfs_check docker-nfs-check

And what it does is list the service definitions available in directory /etc/sysconfig/docker-nfs-check/.

# File: /etc/sysconfig/docker-nfs-check/photoprism
# dot-sourced by /usr/local/bin/docker-nfs-check
# To load this file, you must set DOCKER_SERVICE to match this filename.
# su to this user and then
DS_USER="photoprism"
# cd to this path
DS_PATH="/home/photoprism/photoprism"
# to run the docker-compose command on this container name
DS_CONTAINER="photoprism"
# how many lines should return from docker-compose exec ${this_filename} mount | grep nfs
DS_LINES=3
# if the lines are incorrect, restart this systemd service
DS_SERVICE="photoprism.service"

This is indeed a ridiculous hack and work-around, but it works for me. And clearly I'm running out of good blog topics I'm actually going to bother to write.

Comments