Skip to content

Instantly share code, notes, and snippets.

@papamoose
Last active February 4, 2024 00:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save papamoose/826a975b19f10926360c032cd982687c to your computer and use it in GitHub Desktop.
Save papamoose/826a975b19f10926360c032cd982687c to your computer and use it in GitHub Desktop.
Wait for ThunderBay 6 to be connected via Thunderbolt 3 before attempting to mount zpool.
#!/bin/bash
# This exists because I couldn't figure out to to make
# any of the relevant system units wait for my zpool to become available
# before importing it.
#
# zpool `tank` is a ThunderBay 6 connected via Thunderbolt 3.
#
# bolt.service -> ? -> zfs-import-cache
# ? is possibly just time as it takes a bit for the drives to spin up.
# The nvme pools work fine, for example.
#
# I hate that this script has to exist.
# If you have better ideas let me know.
# Good luck...
function is_zpool_imported(){
zpool="$1"
ec=$(zpool status $zpool >/dev/null 2>&1; echo $?)
echo $ec
# 0: yes it is imported
# anything else you have a problem
}
function is_zpool_mounted(){
# 0: imported, mounted
# 1: NOT imported, NOT mounted
# 2: imported, NOT mounted, directory does NOT exist
# 3: imported, NOT mounted, directory exists
zpool="$1"
if [[ $(is_zpool_imported $zpool) -eq 0 ]]; then
# check /proc/mount
ec=$(grep -qs "^${zpool} " /proc/mounts; echo $?)
if [[ $ec -eq 0 ]]; then
echo 0
else
# imported but NOT mounted
# check if directory exists
d=$(zfs get mountpoint $zpool -H -o value)
if [[ -d $d ]]; then
# imported, NOT mounted, directory exists
echo 3
else
#imported, NOT mounted, directory does NOT exist
echo 2
fi
fi
else
# zpool not imported
echo 1
fi
}
function findboltdevice(){
pattern="$1" # user provides a pattern to match
ret=1 # default is no match
for m in /sys/bus/thunderbolt/devices/*/device_name; do
c=$(cat $m)
if [[ $c =~ $pattern ]]; then
ret=0 # matched
fi
done
echo $ret # 0:matched, 1: not matched
}
function zpoolavail(){
zpool="$1"
ret=1
c=$(zpool import|grep -qs "pool: ${zpool}"; echo $?)
if [[ $c -eq 0 ]]; then
ret=0
fi
echo $ret
}
function importzpool(){
zpool="$1"
while true; do
ec=$( zpoolavail $zpool )
if [[ $ec -eq 0 ]]; then
echo "Importing $zpool"
zpool import $zpool
break
fi
echo "Waiting on zpool to become available"
/bin/sleep 5
done
}
function main(){
zpool="$1"
# Start bolt if it's not active already
# wait cause it takes time for the external disks to become available. I hate this.
# https://www.kernel.org/doc/html/v5.5/admin-guide/thunderbolt.html
systemctl is-active --quiet bolt.service || systemd start bolt.service
# wait until Thunderbay is recognized
# This is NOT a good test because we still need a loop to determine when the pool is available to 'zpool import'
while true; do
ec=$( findboltdevice 'ThunderBay')
if [[ $ec -eq 0 ]]; then
break
fi
echo 'Waiting for ThunderBay to activate...'
/bin/sleep 5
done
ec=$(is_zpool_mounted $zpool)
if [[ $ec -eq 0 ]]; then
echo "$zpool already imported and mounted!"
elif [[ $ec -eq 1 ]]; then
echo "Import then mount $zpool"
# there could be problems if the directory already exists
# at this point we don't know what the directory it mounts to is
importzpool $zpool # this should also automount so the next few lines are probably useless
ec=$(is_zpool_mounted $zpool)
if [[ $ec -gt 1 ]]; then
zfs mount $zpool
fi
elif [[ $ec -eq 2 ]]; then
echo "Mounting $zpool"
zfs mount $zpool
elif [[ $ec -eq 3 ]]; then
echo "Remove directory then mount"
d=$(zfs get mountpoint $zpool -H -o value)
if [[ -d "$d" ]]; then
# I'm not confident in this script to actually remove data directories
# Just printing it out here so you know what to do.
echo "rm -rI $d"
fi
zfs mount $zpool
fi
# before starting docker ensure zpool is mounted
ec=$(is_zpool_mounted $zpool)
if [[ $ec -eq 0 ]]; then
echo "Starting docker"
systemctl start docker
else
echo "Something went wrong mounting $zpool. Not starting docker."
fi
}
main 'tank'
[Unit]
Description="Mount zpool 'tank' after bolt.service and start docker"
Requires=bolt.service
Requires=zfs.target
After=bolt.service
Before=zfs.target
[Service]
Type=oneshot
#ExecStartPre=/bin/sleep 30
ExecStart=/usr/local/sbin/bolt-zfs-docker-startup
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment