#!/usr/bin/env bash

while getopts ":s" opt; do
  case $opt in
    s)
      SSD="true"
      ;;
  esac
done

SSD="${SSD:-false}"

# Required tools
DOCKER="${DOCKER:-docker}"
NSENTER="${NSENTER:-nsenter}"
BRIDGE="${BRIDGE:-bridge}"
IPTABLES="${IPTABLES:-iptables}"
IPVSADM="${IPVSADM:-ipvsadm}"
IP="${IP:-ip}"
SSDBIN="${SSDBIN:-ssd}"
JQ="${JQ:-jq}"

networks=0
containers=0
ip_overlap=0

NSDIR=/var/run/docker/netns

function die {
    echo $*
    exit 1
}

function echo_and_run {
  echo "#" "$@"
  eval $(printf '%q ' "$@") < /dev/stdout
}

function check_ip_overlap {
  inspect=$1
  overlap=$(echo "$inspect_output" | grep "EndpointIP\|VIP" | cut -d':' -f2 | sort | uniq -c | grep -v "1 ")
  if [ ! -z "$overlap" ]; then
    echo -e "\n\n*** OVERLAP on Network ${networkID} ***";
    echo -e "${overlap} \n\n"
    ((ip_overlap++))
  else
    echo "No overlap"
  fi
}

type -P ${DOCKER} > /dev/null || echo "This tool requires the docker binary"
type -P ${NSENTER} > /dev/null || echo "This tool requires nsenter"
type -P ${BRIDGE} > /dev/null || echo "This tool requires bridge"
type -P ${IPTABLES} > /dev/null || echo "This tool requires iptables"
type -P ${IPVSADM} > /dev/null || echo "This tool requires ipvsadm"
type -P ${IP} > /dev/null || echo "This tool requires ip"
type -P ${JQ} > /dev/null || echo "This tool requires jq"

if ${DOCKER} network inspect --help | grep -q -- --verbose; then
    NETINSPECT_VERBOSE_SUPPORT="--verbose"
else
    NETINSPECT_VERBOSE_SUPPORT=""
fi

echo "Host iptables"
echo_and_run ${IPTABLES} -w1 -n -v -L -t filter | grep -v '^$'
echo_and_run ${IPTABLES} -w1 -n -v -L -t nat | grep -v '^$'
echo_and_run ${IPTABLES} -w1 -n -v -L -t mangle | grep -v '^$'
printf "\n"

echo "Host links addresses and routes"
echo_and_run ${IP} -o link show
echo_and_run ${IP} -o -4 address show
echo_and_run ${IP} -4 route show
printf "\n"

echo "Overlay network configuration"
for networkID in $(${DOCKER} network ls --no-trunc --filter driver=overlay -q) "ingress_sbox"; do
    echo "nnn Network ${networkID}"
    if [ "${networkID}" != "ingress_sbox" ]; then
        nspath=($(ls ${NSDIR}/*${networkID:0:9}*))
        inspect_output=$(${DOCKER} network inspect ${NETINSPECT_VERBOSE_SUPPORT} ${networkID})
        echo "$inspect_output"
        check_ip_overlap $inspect_output
    else
        nspath=(${NSDIR}/${networkID})
    fi

    for i in "${nspath[@]}"
    do
      echo_and_run ${NSENTER} --net=${i} ${IP} -o -4 address show
      echo_and_run ${NSENTER} --net=${i} ${IP} -4 route show
      echo_and_run ${NSENTER} --net=${i} ${IP} -4 neigh show
      bridges=$(${NSENTER} --net=${i} ${IP} -j link show type bridge | ${JQ} -r '.[].ifname')
      # break string to array
      bridges=(${bridges})
      for b in "${bridges[@]}"
      do
        if [ -z ${b} ] || [ ${b} == "null" ]; then
          continue
        fi
        echo_and_run ${NSENTER} --net=${i} ${BRIDGE} fdb show br ${b}
      done
      echo_and_run ${NSENTER} --net=${i} ${IPTABLES} -w1 -n -v -L -t filter | grep -v '^$'
      echo_and_run ${NSENTER} --net=${i} ${IPTABLES} -w1 -n -v -L -t nat | grep -v '^$'
      echo_and_run ${NSENTER} --net=${i} ${IPTABLES} -w1 -n -v -L -t mangle | grep -v '^$'
      echo_and_run ${NSENTER} --net=${i} ${IPVSADM} -l -n
      printf "\n"
      ((networks++))
    done
done

echo "Container network configuration"
while read containerID status; do
    echo "ccc Container ${containerID} state: ${status}"
    ${DOCKER} container inspect ${containerID} --format 'Name:{{json .Name | printf "%s\n"}}Id:{{json .Id | printf "%s\n"}}Hostname:{{json .Config.Hostname | printf "%s\n"}}CreatedAt:{{json .Created | printf "%s\n"}}State:{{json .State|printf "%s\n"}}RestartCount:{{json .RestartCount | printf "%s\n" }}Labels:{{json .Config.Labels | printf "%s\n"}}NetworkSettings:{{json .NetworkSettings}}' | sed '/^State:/ {s/\\"/QUOTE/g; s/,"Output":"[^"]*"//g;}'
    if [ ${status} = "Up" ]; then
        nspath=$(docker container inspect --format {{.NetworkSettings.SandboxKey}} ${containerID})
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IP} -o -4 address show
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IP} -4 route show
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IP} -4 neigh show
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IPTABLES} -w1 -n -v -L -t nat | grep -v '^$'
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IPTABLES} -w1 -n -v -L -t mangle | grep -v '^$'
        echo_and_run ${NSENTER} --net=${nspath[0]} ${IPVSADM} -l -n
        ((containers++))
    fi
    printf "\n"
done < <(${DOCKER} container ls -a --format '{{.ID}} {{.Status}}' |cut -d' ' -f1,2)

if [ "true" == ${SSD} ] ; then
    echo "" ; echo "#### SSD control-plane and datapath consistency check on a node ####"
    for netName in $(docker network ls -f driver=overlay --format "{{.Name}}") ; do
        echo "## $netName ##"
        ${SSDBIN} $netName
        echo ""
    done
fi

echo -e "\n\n==SUMMARY=="
echo -e "\t Processed $networks networks"
echo -e "\t IP overlap found: $ip_overlap"
echo -e "\t Processed $containers running containers"
