#!/bin/bash

usage() {
    echo "$0 (launch|stop)"
}

SCOPE_IMAGE=weaveworks/scope
CONTAINER_NAME=weavescope
DNS_CONTAINER_NAME=weavedns
DNS_HTTP_PORT=6785
HOSTNAME=scope
DOMAINNAME=weave.local
FQDN=$HOSTNAME.$DOMAINNAME
DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0}
IP_REGEXP="[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"

[ $# -gt 0 ] || usage
COMMAND=$1
shift 1

dns_running() {
    status=$(docker inspect --format='{{.State.Running}}' $DNS_CONTAINER_NAME 2>/dev/null) && [ "$status" = "true" ]
    return $?
}

# Check that a container named $1 with image $2 is not running
check_not_running() {
    case $(docker inspect --format='{{.State.Running}} {{.Config.Image}}' $1 2>/dev/null) in
        "true $2")
            echo "$1 is already running." >&2
            exit 1
            ;;
        "true $2:"*)
            echo "$1 is already running." >&2
            exit 1
            ;;
        "false $2")
            docker rm $1 >/dev/null
            ;;
        "false $2:"*)
            docker rm $1 >/dev/null
            ;;
        true*)
            echo "Found another running container named '$1'. Aborting." >&2
            exit 1
            ;;
        false*)
            echo "Found another container named '$1'. Aborting." >&2
            exit 1
            ;;
    esac
}

docker_bridge_ip() {
    DOCKER_BRIDGE_IP=$(ip -4 addr show dev $DOCKER_BRIDGE | grep -m1 -o 'inet [.0-9]*')
    DOCKER_BRIDGE_IP=${DOCKER_BRIDGE_IP#inet }
}

# Perform operation $1 on local DNS database, for container ID $2
# with FQDN $3, at addresses $4, $5 ... This function is only called
# where we know $2 is a valid container name
tell_dns_fqdn() {
    METHOD="$1"
    CONTAINER_ID="$2"
    CONTAINER_FQDN="$3"
    shift 3
    if ! dns_running; then
        # weavedns not running - silently return
        return
    fi
    # get the long form of the container ID
    CONTAINER=$(docker inspect --format='{{.Id}}' $CONTAINER_ID 2>/dev/null)
    MORE_ARGS="--data-urlencode fqdn=$CONTAINER_FQDN"
    for ADDR; do
        http_call $DNS_CONTAINER_NAME $DNS_HTTP_PORT $METHOD /name/$CONTAINER/${ADDR%/*} $MORE_ARGS || true
    done
}

# Call url $4 with http verb $3 on container $1 at port $2
http_call() {
    container_ip $1 \
        "$1 container is not present. Have you launched it?" \
        "$1 container is not running." \
        || return 1
    shift 1
    http_call_ip $CONTAINER_IP "$@"
}

http_call_ip() {
    ip="$1"
    port="$2"
    http_verb="$3"
    url="$4"
    shift 4
    curl --connect-timeout 3 -s -X $http_verb "$@" http://$ip:$port$url
}

container_ip() {
    if ! status=$(docker inspect --format='{{.State.Running}} {{.NetworkSettings.IPAddress}}' $1 2>/dev/null); then
        echo "$2" >&2
        return 1
    fi
    case "$status" in
        "true ")
            echo "$1 container has no IP address; is Docker networking enabled?" >&2
            return 1
            ;;
        true*)
            CONTAINER_IP="${status#true }"
            ;;
        *)
            echo "$3" >&2
            return 1
            ;;
    esac
}

case "$COMMAND" in

	launch)
		[ $# -eq 0 ] || usage
		check_not_running $CONTAINER_NAME $IMAGE

		# If WeaveDNS is running, we want to automatically tell the scope
		# image to use weave dns.  We can't use --dns with --net=host, so we have to hack it.
		if dns_running; then
			docker_bridge_ip
			WEAVESCOPE_DNS_ARGS="--dns $DOCKER_BRIDGE_IP --searchpath $DOMAINNAME"
		fi

		CONTAINER=$(docker run --privileged -d --name=$CONTAINER_NAME --net=host --pid=host \
			-v /var/run/docker.sock:/var/run/docker.sock \
			$WEAVESCOPE_DOCKER_ARGS $SCOPE_IMAGE $WEAVESCOPE_DNS_ARGS "$@")

		if dns_running; then
			IP_ADDRS=$(find /sys/class/net -name eth* | xargs -n1 basename | xargs -n1 ip addr show |
				grep inet | awk '{ print $2 }' | grep -oE "$IP_REGEXP" | xargs echo)
			tell_dns_fqdn PUT $CONTAINER $FQDN $IP_ADDRS
		fi

		echo $CONTAINER
		;;

	stop)
		[ $# -eq 0 ] || usage
		if ! docker stop $CONTAINER_NAME >/dev/null 2>&1 ; then
			echo "Weave Scope is not running." >&2
		fi
		docker rm -f $CONTAINER_NAME >/dev/null 2>&1 || true
		;;

	*)
		echo "Unknown scope command '$COMMAND'" >&2
		usage
		;;

esac
