#!/bin/bash
#
# Copyright 2013 Hewlett-Packard Development Company, L.P.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

set -e
set -o pipefail

SCRIPT_NAME=$(basename $0)
SCRIPT_HOME=$(dirname $0)

PATH=$PATH:/usr/sbin:/sbin

# Some defaults
ARCH=i386
export IMAGE_NAME=seed
export DIB_IMAGE_SIZE=30
BUILD_ONLY=
CREATE_IMAGE=yes
ALWAYS_ELEMENTS="vm cloud-init-nocloud local-config boot-stack seed-stack-config nova-ironic"
DIB_COMMON_ELEMENTS=${DIB_COMMON_ELEMENTS:-''}
SEED_DIB_EXTRA_ARGS=${SEED_DIB_EXTRA_ARGS:-'rabbitmq-server'}

if [ "${USE_MARIADB:-}" = 1 ] ; then
    SEED_DIB_EXTRA_ARGS="$SEED_DIB_EXTRA_ARGS mariadb-rpm"
fi

if [[ "$DIB_COMMON_ELEMENTS $SEED_DIB_EXTRA_ARGS" != *enable-serial-console* ]]; then
    SEED_DIB_EXTRA_ARGS="$SEED_DIB_EXTRA_ARGS remove-serial-console"
fi
export VM_IP=""

function show_options {
    echo "Usage: $SCRIPT_NAME [options] <element> [<element> ...]"
    echo
    echo "Create and start a VM by combining the specified elements"
    echo "with common default elements, assuming many things about"
    echo "the local operating environment."
    echo "See ../scripts/devtest.sh"
    echo
    echo "The environment variable TE_DATAFILE must be set, pointing at a test"
    echo "environment JSON file. If seed-ip is present in the JSON then that is"
    echo "used for the VM IP address, otherwise it is discovered by probing the"
    echo "ARP table and then saved back into the JSON file."
    echo
    echo "If host-ip (and possibly ssh-user) is set in the JSON then those details"
    echo "are used to construct a remote libvirt URL and spawn the VM remotely."
    echo "Note that seed-ip *must* be present when doing this. When spawning remotely"
    echo "the image is copied to that host via rsync, and a remote virsh URI is used."
    echo "However SSH access with rsync write access to /var/lib/libvirt/images/,"
    echo "permission to chattr, and the ability to run virsh as the selected user are"
    echo "requirements."
    echo
    echo "Options:"
    echo "      -a i386|amd64     -- set the architecture of the VM (i386)"
    echo "      --build-only      -- build the needed images but don't deploy them."
    echo "      -o name           -- set the name of the VM and image file"
    echo "                           (seed) - must match that from setup-seed-vm"
    echo "      -s size           -- set the image size (30 GB)"
    echo "      -c                -- use a image cache for seed image"
    echo "      -i                -- image file was built elsewhere, don't"
    echo "                           create"
    echo
    exit $1
}

TEMP=$(getopt -o hcia:o:s: -l build-only -n $SCRIPT_NAME -- "$@")
if [ $? != 0 ]; then
    echo "Terminating..." >&2;
    exit 1;
fi

# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -a) export ARCH=$2; shift 2 ;;
        --build-only) BUILD_ONLY="1"; shift 1;;
        -o) export IMAGE_NAME=$2; shift 2 ;;
        -s) export DIB_IMAGE_SIZE=$2; shift 2 ;;
        -h) show_options 0;;
        -c) export IMAGE_CACHE_USE=1; shift ;;
        -i) export CREATE_IMAGE=; shift ;;
        --) shift ; break ;;
        *) echo "Error: unsupported option $1." ; exit 1 ;;
    esac
done

for arg; do
    SEED_DIB_EXTRA_ARGS="$SEED_DIB_EXTRA_ARGS $arg";
done

SEED_ARCH=

case $ARCH in
    i386) SEED_ARCH='i686'; ;;
    amd64|x86_64) SEED_ARCH='x86_64'; ;;
    *) echo "Unsupported arch $ARCH!" ; exit 1 ;;
esac

if [ -z "$TE_DATAFILE" ]; then
    echo "Error: TE_DATAFILE not set."
    show_options 1
fi

HOST_IP=$(os-apply-config -m $TE_DATAFILE --key host-ip --type netaddress --key-default '')
REMOTE_OPERATIONS=$(os-apply-config -m $TE_DATAFILE --key remote-operations --type raw --key-default '')
if [ -n "$HOST_IP" ]; then
    SSH_USER=$(os-apply-config -m $TE_DATAFILE --key ssh-user --type raw --key-default '')
    if [ -n "$SSH_USER" ]; then
        SSH_USER="${SSH_USER}@"
    fi
    VM_HOST=${SSH_USER}${HOST_IP}
    echo $VM_HOST
fi

ENV_NUM=$(os-apply-config -m $TE_DATAFILE --key env-num --type int --key-default 0)

if [ $CREATE_IMAGE  ]; then

    ELEMENTS_PATH=${ELEMENTS_PATH:-$SCRIPT_HOME/../../tripleo-image-elements/elements}
    export ELEMENTS_PATH

    DIB_PATH=${DIB_PATH:-$SCRIPT_HOME/../../diskimage-builder}
    DIB=$(which disk-image-create || echo $DIB_PATH/bin/disk-image-create)

    if [ ! -e $DIB ]; then
        echo "Error: unable to locate disk-image-create"
        exit 1
    fi

fi

# Shutdown any running VM - writing to the image file of a running VM is a
# great way to get a corrupt image file.
if [ -z "$BUILD_ONLY" ]; then
    if [ -n "$REMOTE_OPERATIONS" ]; then
        ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no ${VM_HOST} virsh destroy ${IMAGE_NAME}_$ENV_NUM || true
        # Ensure any existing VM's in the test environment are shutdown, so devtest always starts at a consistent point.
        for NUM in $(seq 0 14) ; do
            ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no ${VM_HOST} virsh destroy baremetalbrbm${ENV_NUM}_${NUM} || true
        done
    else
        virsh destroy $IMAGE_NAME || true
        for NUM in $(seq 0 14) ; do
            virsh destroy baremetal_${NUM} || true
        done
    fi
fi

if [ $CREATE_IMAGE  ]; then

    IMAGE_CACHE_FILE=$TRIPLEO_ROOT/seed

    # Create the image if it doesn't exist or we're not using image cache
    if [ ! -e "$IMAGE_CACHE_FILE.qcow2" -o -z "$IMAGE_CACHE_USE" ] ; then
        $DIB -x -u -a $ARCH $ALWAYS_ELEMENTS $DIB_COMMON_ELEMENTS $SEED_DIB_EXTRA_ARGS -o $IMAGE_CACHE_FILE 2>&1 | tee $IMAGE_CACHE_FILE.log
    else
        echo "Using cached seed image : $IMAGE_CACHE_FILE.qcow2"
    fi
    if [ -n "$BUILD_ONLY" ]; then
        exit 0
    fi

    if [ -n "$REMOTE_OPERATIONS" ]; then
        # rsync could be used here which may have been more efficient but using a
        # custom command "copyseed" should be easier to restrict. Also we can
        # take multiple steps on the server in this single command meaning we
        # don't have to open up the ssh access even further.
        dd if=$IMAGE_CACHE_FILE.qcow2 | ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no ${VM_HOST} copyseed $ENV_NUM
    else
        sudo cp $IMAGE_CACHE_FILE.qcow2 /var/lib/libvirt/images/$IMAGE_NAME.qcow2
        sudo chattr +C /var/lib/libvirt/images/$IMAGE_NAME.qcow2 || true
    fi
fi

function poll_vm {
    if [ -z "$VM_IP" ]; then
        MAC=$(sudo virsh dumpxml $IMAGE_NAME | grep "mac address" | head -1 | awk -F "'" '{print $2}')
        VM_IP=$(arp -n | grep $MAC | awk '{print $1}')
    fi
    [ -z $VM_IP ] && return 1
    ping -c 1 $VM_IP || return 1
    return 0
}
export -f poll_vm

if [ -n "$REMOTE_OPERATIONS" ]; then
    ssh -o StrictHostKeyChecking=no -o PasswordAuthentication=no ${VM_HOST} virsh start ${IMAGE_NAME}_$ENV_NUM
    VM_IP=$(os-apply-config -m $TE_DATAFILE --key seed-ip --type netaddress --key-default '')
else
    sudo virsh start $IMAGE_NAME
fi

echo "Waiting for $IMAGE_NAME VM to boot."
wait_for -w 100 --delay 1 -- poll_vm
poll_vm

echo
echo "Booted. Found IP: $VM_IP."

# hostkeys are generated by cloud-init as part of the boot sequence - can
# take a few seconds.
echo "Waiting for SSH hostkey."
wait_for -w 30 --delay 1 -- "ssh-keyscan $VM_IP 2>&1 | grep \"$VM_IP.*OpenSSH\""

# Remove the hostkey, new instance == new key.
ssh-keygen -R $(os-apply-config -m $TE_DATAFILE --key baremetal-network.seed.ip --type netaddress --key-default '192.0.2.1') || true

echo "element(s): $ALWAYS_ELEMENTS $DIB_COMMON_ELEMENTS $SEED_DIB_EXTRA_ARGS booted and ready."
echo "SEED_IP=$VM_IP"
echo
echo "to login:   ssh root@$VM_IP"
NEW_JSON=$(jq '.["seed-ip"]="'${VM_IP}'"' $TE_DATAFILE)
echo "$NEW_JSON" > $TE_DATAFILE
