#!/bin/bash -e

BASENAME=$(basename $0)

USAGE="Usage: $0 [options]
Options:
    -c|--channel CHANNEL
                channel name (stable/beta/alpha)               [default: stable]
    -i|--base-image BASE_IMAGE
                path to base image
                      [default: ~/.qemu/coreos_stable_production_qemu_image.img]
    -p|--ssh-port PORT
                The port on localhost to map to the VM's sshd. [default: 2244]
    -v|--verbose  Make verbose
    -h|--help     this help message

This script is a wrapper around qemu for starting CoreOS virtual machines,
especially for running functional tests automatically.
The -c option can be used to specify a channel name: stable, beta, or alpha.
The -p option may be used to specify a particular ssh port on localhost to
map to sshd of the VM.
The channel name can be overridden by environment variable COREOS_CHANNEL,
and port number can be also overridden by environment variable COREOS_SSH_PORT.
"

while [ $# -ge 1 ]; do
    case "$1" in
        -c|--channel)
            OPTVAL_CHANNEL="$2"
            shift 2 ;;
        -i|--base-image)
            OPTVAL_BASE_IMAGE="$2"
            shift 2 ;;
        -p|--ssh-port)
            OPTVAL_SSH_PORT="$2"
            shift 2 ;;
        -v|--verbose)
            set -x
            shift ;;
        -h|-help|--help)
            echo "$USAGE"
            exit ;;
        *)
            break ;;
    esac
done


function print_info {
  echo "$BASENAME: INFO: $@"
}

function print_warning {
  echo "$BASENAME: WARNING: $@"
}

function print_error {
  echo "$BASENAME: ERROR: $@"
  exit 1
}

if ! qemu-system-x86_64 --version > /dev/null 2>&1; then
  print_error "Please install QEMU first"
fi

CDIR=$(cd `dirname $0` && pwd)
cd $CDIR

ARGS=`for i in "$@"; do printf '%q ' "$i"; done`

CONFIG_DIR=$(mktemp -t -d coreos-configdrive.XXXXXXXXXX)
mkdir -p "${CONFIG_DIR}/openstack/latest"
QEMU_DIR=$HOME/.qemu
mkdir -p $QEMU_DIR
MAX_SSH_TRIES=60
SSH_KEYS=$(cat fixtures/id_rsa.pub)
PID_FILE=$(mktemp)
NAME=fleet-tester

# The ssh port number is set to 2244, channel is stable by default respectively.
# They can be overridden by environment variables, e.g.
#
#  $ COREOS_SSH_PORT=2245 COREOS_CHANNEL=alpha ./run-in-qemu

: ${COREOS_SSH_PORT:=2244}
if [ -n "$OPTVAL_SSH_PORT" ]; then
  COREOS_SSH_PORT=$OPTVAL_SSH_PORT
fi

: ${COREOS_CHANNEL:=stable}
if [ -n "$OPTVAL_CHANNEL" ]; then
  COREOS_CHANNEL=$OPTVAL_CHANNEL
fi

: ${BASE_IMAGE:=${QEMU_DIR}/coreos_${COREOS_CHANNEL}_production_qemu_image.img}
if [ -n "$OPTVAL_BASE_IMAGE" ]; then
  BASE_IMAGE=$OPTVAL_BASE_IMAGE
fi

IMAGE=$QEMU_DIR/coreos_${COREOS_CHANNEL}_fleet_test.qcow2

IMG_URL="https://${COREOS_CHANNEL}.release.core-os.net/amd64-usr/current/coreos_production_qemu_image.img.bz2"
SIG_URL="https://${COREOS_CHANNEL}.release.core-os.net/amd64-usr/current/coreos_production_qemu_image.img.bz2.sig"
GPG_PUB_KEY="https://coreos.com/security/image-signing-key/CoreOS_Image_Signing_Key.asc"
GPG_PUB_KEY_ID="50E0885593D2DCB4"

set +e
if gpg --version > /dev/null 2>&1; then
  GPG=true
  if ! gpg --list-sigs $GPG_PUB_KEY_ID > /dev/null; then
    curl -s $GPG_PUB_KEY | gpg --import --keyid-format LONG || (GPG=false && print_warning "Can not import GPG public key")
  fi
else
  GPG=false
  print_warning "Please install GPG to verify CoreOS images' signatures"
fi
set -e

trap 'rm -f "$BASE_IMAGE" && rm -f "$PID_FILE" && rm -rf "$CONFIG_DIR"' INT TERM EXIT
if [ ! -f "$BASE_IMAGE" ]; then
  if [ $GPG ]; then
    LANG=en_US gpg --enable-special-filenames \
        --verify \
        --batch \
        <(curl -s $SIG_URL) \
        <(curl --progress-bar $IMG_URL | tee >(bzcat > $BASE_IMAGE)) || (rm -f $BASE_IMAGE && print_error "Failed to download and verify the image")
  else
    curl --progress-bar $IMG_URL | bzcat > $BASE_IMAGE || (rm -f $BASE_IMAGE && print_error "Failed to download the image")
  fi
fi
trap - INT TERM EXIT
trap

trap 'kill $QEMU_PID; rm -f "$PID_FILE" && rm -rf "$CONFIG_DIR" && rm -f "$IMAGE"' EXIT

sed "s#---#ssh_authorized_keys:\n - \"$SSH_KEYS\"#" user-data > ${CONFIG_DIR}/openstack/latest/user_data

qemu-img create -f qcow2 -b $BASE_IMAGE $IMAGE || print_error "Failed to create $IMAGE disk image"

qemu-system-x86_64 \
  -name $NAME \
  -m 512 \
  -net nic,vlan=0,model=virtio \
  -net user,vlan=0,hostfwd=tcp:127.0.0.1:$COREOS_SSH_PORT-:22,hostname=$NAME \
  -drive if=virtio,file=$IMAGE \
  -fsdev local,id=conf,security_model=none,readonly,path=$CONFIG_DIR \
  -fsdev local,id=fleet,security_model=none,path=$CDIR/../ \
  -device virtio-9p-pci,fsdev=conf,mount_tag=config-2 \
  -device virtio-9p-pci,fsdev=fleet,mount_tag=fleet \
  -machine accel=kvm \
  -cpu host \
  -smp 1 \
  -daemonize \
  -display none \
  -serial none \
  -pidfile $PID_FILE

QEMU_PID=$(cat $PID_FILE)

TRY=0
while true; do
  TRY=$((TRY+1))
  if [ $TRY -gt $MAX_SSH_TRIES ]; then
    print_error "Can not connect to ssh, exiting..."
  fi
  print_info "Trying to connect to qemu VM, #${TRY} of #${MAX_SSH_TRIES}..."
  set +e
  RES=$(LANG=en_US ssh -l core -o ConnectTimeout=1 -o PasswordAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $COREOS_SSH_PORT -i fixtures/id_rsa 127.0.0.1 "ls ~/fleet/functional/test" 2>&1)
  RES_CODE=$?
  set -e
  if [ $RES_CODE -eq 0 ]; then
    break
  else
    echo "$RES" | grep -Eq "(refused|No such file or directory|reset by peer|closed by remote host|authentication failure)" && sleep 1 || true
  fi
done

ssh -l core -o PasswordAuthentication=no -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p $COREOS_SSH_PORT -i fixtures/id_rsa 127.0.0.1 "sudo ~/fleet/functional/test $ARGS"
