#!/bin/bash -e ########################################################################### if [ ! -x "$1" ] then echo >&2 "Usage: $0 " 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 modcount=0 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 modcount=$(( modcount + 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 [ "$modcount" -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