#!/bin/bash

# Comment this out or set it to 'false' to actually make the changes
debugRun='true'

# Change this to how far you'd like to diminish the difference to
acceptableVariance=50

# Some public variable assignments
highAgent=''
lowAgent=''
declare -A counts


echo "Building network and agent lists..."
# Retrieve all the DHCP agent GUIDs
agents="$(neutron agent-list | awk '/dhcp-agent/ { print $2 }')"
agentCount=$(echo "$agents" | wc -l)
# Retrieve all the network GUIDs
networks="$(openstack network list | tail -n +4 | head -n -1 | awk ' { print $2 } ')"

while : ; do
    echo "Checking current DHCP network/agent assignments..."

    # Parse our network GUID counts from our DHCP agents, store them
    #  in $counts as $count[guid]=count
    for agent in $agents; do
        counts[$agent]=$(neutron agent-show $agent | grep -o '"networks": [^ ]*' | cut -d' ' -f2)
    done

    # Iterate through identified servers
    for server in ${!counts[@]}; do
        # assign the name of the one with the highest count to highAgent
        if [[ -z "$highAgent" ]] || [[ ${counts[$server]} -gt ${counts[$highAgent]} ]]; then
            highAgent=$server
        fi
        # and similarly, lowest to lowAgent
        if [[ -z "$lowAgent" ]] || [[ ${counts[$server]} -lt ${counts[$lowAgent]} ]]; then
            lowAgent=$server
        fi
    done
    # Identify the difference
    diff=$(( ${counts[$highAgent]} - ${counts[$lowAgent]} ))
    # Some helpful output
    echo "High agent: $highAgent - ${counts[$highAgent]}"
    echo "Low agent: $lowAgent - ${counts[$lowAgent]}"
    echo "Difference: $diff"
    echo "Acceptable Variance: $acceptableVariance"

    if [[ $diff -gt $acceptableVariance ]]; then
        echo "Reassigning networks from $highAgent"
        echo
        # A variable to keep us from going crazy on reassignments
        thisRun=0
        # Iterate through all networks
        for network in $networks; do
            # If we haven't reassigned more than we need
            #   (note: split the difference in half to prevent overlevelling, this
            #       may result in more runs, but we're less likely to overshoot on
            #       just one run)
            if [[ $thisRun -lt $(( $diff / 2 )) ]]; then
                # If the network is assigned to the highAgent
                if neutron dhcp-agent-list-hosting-net $network | grep -q $highAgent; then
                    # Increment our run count
                    let "thisRun+=1"
                    # Pick a random agent to assign it to
                    newAgent=$(echo "$agents" | head -$(( $RANDOM % $agentCount + 1 )) | tail -1)
                    # Don't bother assigning it to itself
                    if [[ $newAgent != $highAgent ]]; then
                        echo "Reassigning $network from $highAgent to $newAgent."
                        # Skip actual assignments if we're on a debug run
                        if [[ -z $debugRun ]] || [[ $debugRun == 'false' ]]; then
                            neutron dhcp-agent-network-remove $highAgent $network >/dev/null
                            neutron dhcp-agent-network-add $newAgent $network >/dev/null
                        fi
                    fi
                fi
            else
                continue
            fi
        done
    else
        # If the difference is within the acceptable variance, break our loop.
        echo "No reassignment necessary!"
        break
    fi
    if [[ $debugRun == 'true' ]]; then
        echo "Aborting successive runs for debug"
        break
    fi
done