#!/bin/bash
# this command helper depends on key-based (passwordless) SSH access by the current user to each of the docker swarm nodes.
# usage help.
usage()
{
    echo
    echo "Usage: docker-service-exec [OPTIONS] SERVICE COMMAND [ARG...]"
    echo
    echo "Run a command in a running swarm service"
    echo
    echo "Options:
  -i, --interactive          Keep STDIN open even if not attached
  -u, --user string          Username or UID (format: <name|uid>[:<group|gid>])
  -w, --workdir string       Working directory inside the container"
  exit 2
}

# parse the arguments
PARSED_ARGUMENTS=$(getopt -q -a -n docker-service-exec -o iu:w: -l interactive,it,user:,workdir: -- "$@")
VALID_ARGUMENTS=$?
if [ "$VALID_ARGUMENTS" != "0" ]; then
  usage
fi

# use below for diagnostics only.
# echo "PARSED_ARGUMENTS is $PARSED_ARGUMENTS"
eval set -- "$PARSED_ARGUMENTS"
while :
do 
  case "$1" in
    -i | --it | --interactive)  OPT_INTERACTIVE="-it"; shift ;;
    -u | --user)                OPT_USER="-u $2"; shift 2 ;;
    -w | --workdir)             OPT_WORKDIR="-w $2"; shift 2 ;;
    # -- means the end of the arguments; drop this, and break out of the while loop
    --) shift; break ;;
    # If invalid options were passed, then getopt should have reported an error,
    # which we checked as VALID_ARGUMENTS when getopt was called...
    *)
    echo "Unexpected option: $1 - this should not happen."
    usage;;
  esac
done

# discover docker server vars.
SERVICE_NAME=$1; shift
TASK_ID=$(docker service ps --filter 'desired-state=running' $SERVICE_NAME -q)
NODE_ID=$(docker inspect --format '{{ .NodeID }}' $TASK_ID)
CONTAINER_ID=$(docker inspect --format '{{ .Status.ContainerStatus.ContainerID }}' $TASK_ID)
NODE_HOST=$(docker node inspect --format '{{ .Description.Hostname }}' $NODE_ID)
# connect to the docker host through SSH
export DOCKER_HOST="ssh://$(whoami)@$NODE_HOST.$(hostname -d)"
# execute the command
docker exec $OPT_INTERACTIVE $OPT_USER $OPT_WORKDIR $CONTAINER_ID "$@"