wireguard-inject/wireguard-inject.sh

164 lines
3.9 KiB
Bash
Executable File

#!/bin/bash -e
###########################################################################
if [ ! -x "$1" ]
then
echo >&2 "Usage: $0 <provisioner script>"
exit 1
fi
# source the provisioner script
. "$1"
printf 'Starting wireguard-inject: %s - %s\n' "$PROVISIONER_NAME" "$(date)"
# other configuration
RUNDIR='/run/wireguard-inject'
[ -d "$RUNDIR" ] || mkdir -m 0700 "$RUNDIR"
MODFILE="${RUNDIR}/${PROVISIONER_NAME}"
###########################################################################
# loop until at least 5 seconds since the last modification date
while :
do
declare -A modtimes
maxmod=0
# scan for modification dates
while IFS= read -r file
do
[ -n "$file" ] || continue
mod=$(stat -c "%Y" "$file")
modtimes[$file]="$mod"
if [ "$mod" -gt "$maxmod" ]
then
maxmod="$mod"
fi
done <<< "$(list_config_files)"
# check the time
now=$(date '+%s')
date_diff=$(( now - maxmod ))
[ "$date_diff" -gt 5 ] && break
# still updates happening, loop around
echo "- waiting for config to settle: $(date)"
sleep $(( 6 - date_diff ))
done
###########################################################################
# compare against the previous run
declare -A interfaces
declare -A previous_modtimes
declare -A add_interfaces
declare -A remove_interfaces
if [ -f "$MODFILE" ]
then
# slurp the previous modtimes into a map
declare -A previous_modtimes
while IFS='!' read -r file mod
do
previous_modtimes[$file]="$mod"
done < "$MODFILE"
fi
# check for changed files
# also, create a map of interfaces to config files along the way
for file in "${!modtimes[@]}"
do
base=${file##*/}
iface=${base%%.*}
interfaces[$iface]="$file"
if [ -v "previous_modtimes[$file]" ] &&
[ "${previous_modtimes[$file]}" -eq "${modtimes[$file]}" ]
then
continue
fi
# if an interface has been modified, remove it then re-add it
remove_interfaces[$iface]=1
add_interfaces[$iface]=1
done
###########################################################################
# fetch a list of configured interfaces
declare -A actual_interfaces
while IFS= read -r iface
do
actual_interfaces[$iface]=1
done <<< "$(list_actual_interfaces)"
###########################################################################
# now we can figure out if interfaces have been added or removed
for iface in "${!actual_interfaces[@]}"
do
# does actual interface exist in config ?
if [ ! -v "interfaces[$iface]" ]
then
# interface has been removed
remove_interfaces[$iface]=1
fi
done
for iface in "${!interfaces[@]}"
do
# does interface actually exist ?
if [ ! -v "actual_interfaces[$iface]" ]
then
# interface has been added
add_interfaces[$iface]=1
# can't remove the interface if it wasn't there in the first place
unset "remove_interfaces[$iface]"
fi
done
###########################################################################
# finally in a position to make some changes
echo " - Removing ${#remove_interfaces[@]} tunnels"
for iface in "${!remove_interfaces[@]}"
do
echo " _ $iface"
remove_tunnel "$iface"
done
echo " - Adding ${#add_interfaces[@]} tunnels"
for iface in "${!add_interfaces[@]}"
do
echo " + $iface"
add_tunnel "$iface" "${interfaces[$iface]}"
done
###########################################################################
# all done
# save the modified times if required
if [ "${#add_interfaces[@]}" -gt 0 ] ||
[ "${#remove_interfaces[@]}" -gt 0 ]
then
exec 3> "$MODFILE"
for file in "${!modtimes[@]}"
do
echo >&3 "${file}!${modtimes[$file]}"
done
exec 3>&-
fi
# also signal the provisioner
all_done
echo "Completed changes: $(date)"
###########################################################################
# end of file