#!/usr/bin/bash
#
# Run ansible on all hosts older than the latest git commit.
# Use argument "$(date)" to update all machines independent
# of the last ansible run.
#
set -eu

## maximal age of file in minutes:
age="15"

pbook="lmn-client"
logdir="/tmp/collector"
debug=false

## date of latest git commit in ansible repository:
git_date="$(date --iso-8601=seconds --date="$(git log --date=iso-strict | \
                                 head -4 | sed -nE "s/^Date:\s+(.+)$/\1/p")")"
echo "Latest commit in git at: $git_date."

if [[ $# = 0 ]] ; then
    timestamp="$git_date"
else
    timestamp="$(date --iso-8601=seconds --date="$1")"
fi
echo "Time stamp at: $timestamp."

#dir="$(mktemp -d)"
dir="/tmp/emitter"
mkdir -vp "$dir"

hlist=""
n=0
running=0
ansible_arg=""

find_outdated(){
    hlist=""
    n=0
    running=0
    ansible_arg="--tags=upgrade"
    while IFS= read -r -d '' file ; do
        running=$(( running + 1 ))
        $debug && echo -n "Processing host '$file' with IP address "
        d="$(sed -nE "s/^2\s+(\S.+)$/\1/p" "$file")"
        if [[ -z "$d" ]] || \
               [[ $(date --date="$d" +%s) -lt $(date --date="$timestamp" +%s) ]] ; then
            r='([0-9]{1,3}\.){3}[0-9]{1,3}'
            ipa="$(sed -nE "s/^3\s+default via.+ src ($r) metric.+/\1/p" "$file")"
            if [[ -z "$ipa" ]] ; then
                # FIXME: Outdated report format, try fallback:
                ipa="$(sed -nE "s|^.+default via.+ src ($r) metric.+|\1|p" "$file" | head -1)"
                echo -ne "\n Outdated '$ipa': $file"
            fi
            ## limit number of hosts addressed in one ansible run:
            [[ n -lt 30 ]] && hlist="$hlist,$ipa"
            n=$(( n + 1 ))
            if [[ $(date --date="$d" +%s) -lt $(date --date="$git_date" +%s) ]] ; then
                ## ansible run needed at least on one machine, run it on all:
                echo -n "✗"
                ansible_arg=""
            else
                echo -n  "U"
            fi
        else
            echo -n '✓'
        fi
    done <  <(find "$logdir" -maxdepth 1 -type f -mmin -$age -print0)
    hlist="${hlist#,}"
    echo -n " $n/$running "
}

run_ansible(){
    local hsts="$1"
    if [[ -n "$hsts" ]] ; then
        if ! echo | eval ANSIBLE_RETRY_FILES_ENABLED=1 ANSIBLE_RETRY_FILES_SAVE_PATH="$dir" \
             ansible-playbook --vault-password-file ~/.vaultpwd \
             -bi inventory.yml "$pbook.yml" "$ansible_arg" -l "$hsts" ; then
            while IFS= read -r ipa ; do
                echo "Ansible for IP address '$ipa' failed."
            done < "$dir/$pbook.retry"
            > "$dir/$pbook.retry"
        fi
    fi
}

#################
while true ; do
    date +%H:%M | tr '\n' ' '
    find_outdated
    run_ansible "$hlist"
    t=$(( 600/(n*n+1) ))
    echo "sleeping ${t}s "
    sleep $t
done