#!/bin/bash

# Copyright 2019 Amazon.com, Inc. or its affiliates. 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. A copy of
# the License is located at
#
# http://aws.amazon.com/apache2.0/
#
# or in the "license" file accompanying this file. This file 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.

# Reads authorized keys blob $3 and prints verified, unexpired keys
# Openssl to use provided as $1
# Signer public key file path provided as $2

# Runs our full suite of integration tests against all known instance types

# Basic string concat w/ newline
concat () {
    printf "%s\n%s" "${1}" "${2}"
}

TOPDIR=$(dirname "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)")

if [ $# -lt 8 ] ; then
    echo "Usage: $0 -r region -a ami -k ec2-key-pair -s subnet -g security-group -p /private/key/path -u ec2-os-user -l ami-linux-distro-name -i /path/to/package/file [-d /test/output/directory] [-t instance,types,list]"
    exit 1
fi

types_specified=0

while getopts ":r:a:k:s:g:d:p:t:u:l:i:" opt ; do
    case "${opt}" in
        r)
            region="${OPTARG}"
            ;;
        a)
            ami_id="${OPTARG}"
            ;;
        k)
            key_name="${OPTARG}"
            ;;
        s)
            subnet_id="${OPTARG}"
            ;;
        g)
            security_group_id="${OPTARG}"
            ;;
        d)
            output_directory="${OPTARG}"
            ;;
        p)
            private_key="${OPTARG}"
            ;;
        t)
            IFS=',' read -r -a instance_types <<< "${OPTARG}"
            types_specified=1
            ;;
        u)
            osuser="${OPTARG}"
            ;;
        l)
            distro="${OPTARG}"
            ;;
        i)
            package_path="${OPTARG}"
            ;;
        *)
            echo "Usage: $0 -r region -a ami -k ec2-key-pair -s subnet -g security-group -p /private/key/path -u ec2-os-user -l ami-linux-distro-name -i /path/to/package/file [-d /test/output/directory] [-t instance,types,list]"
            exit 1
            ;;
    esac
done

# Ensure we have config for this distro
if [ ! -f "${TOPDIR}/integration-test/config/${distro}" ] ; then
    echo "Unsupported distro ${distro} will not be tested"
    exit 1
fi

source "${TOPDIR}/integration-test/config/${distro}"

package_name="${package_path##*/}"

if [ -z "${output_directory}" ] ; then
    timestamp=$(/bin/date -u "+%Y-%m-%d_%H:%M:%S")
    # TODO: Better autogenerated directory.  Include AMI/test name?
    output_directory="/tmp/eic_integ_test_${timestamp}"
    echo "No output directory set.  Creating & using ${output_directory}"
    mkdir "${output_directory}"
fi

# Fetch information about the subnet (AZ, etc)
subnet_output=$(aws ec2 describe-subnets --subnet-ids "${subnet_id}")
subnet_status=$?
if [ "${subnet_status}" -ne 0 ] ; then
    echo "Failed to query subnet information:"
    echo "${subnet_output}"
    exit "${subnet_status}"
fi

zone=$(echo "${subnet_output}" | grep "\"AvailabilityZone\"" | cut -d '"' -f 4)

if [ $types_specified -eq 0 ] ; then
    echo "Instance types not specified.  Will test all supported in this subnet."
    instance_types=$("${TOPDIR}/bin/integration-test/get_zone_instance_types.sh" "${region}" "${zone}")
    IFS=$'\n' read -d '' -r -a instance_types <<< "${instance_types}"
fi

overall_exit=0
for instance_type in "${instance_types[@]}" ; do
    echo "Testing ${instance_type}"
    mkdir "${output_directory}/${instance_type}"
    output=""
    instance_exit=0
    # Run instance
    launch_output=$("${TOPDIR}/bin/integration-test/run_instance.sh" -t "${instance_type}" -a "${ami_id}" -k "${key_name}" -s "${subnet_id}" -g "${security_group_id}" -n "EIC Integration Test ${instance_type}" -r "${region}" -o "${osuser}" -p "${private_key}")
    launch_status=$?
    if [ "${launch_status}" -ne 0 ] ; then
        output=$(concat "${output}" "${launch_output}")
        instance_exit=1
    else
        instance_id=$launch_output
        public_ip=$(aws ec2 describe-instances --instance-ids "${instance_id}" | grep "PublicIp" | cut -d '"' -f 4 | uniq)
        # scp the package file to the instance and install it
        output=$(concat "${output}" "scping package file to instance")
        scp_out=$(scp -i "${private_key}" -o StrictHostKeyChecking=no "${package_path}" "${osuser}@${public_ip}:/tmp/${package_name}" 2>&1)
        install_status=$?
        output=$(concat "${output}" "${scp_out}")
        if [ "${install_status}" -eq 0 ] ; then
            # FIXME: Ubuntu AMIs fail here due to dpkg lock contention
            ssh -i "${private_key}" -o StrictHostKeyChecking=no "${osuser}@${public_ip}" "${INSTALL} /tmp/${package_name}" 1>/dev/null 2>&1
            install_status=$?
            output=$(concat "${output}" "${scp_out}")
        else
            output=$(concat "${output}" "Failed to scp package to instance.")
            instance_exit=1
        fi
        if [ "${install_status}" -ne 0 ] ; then
            output=$(concat "${output}" "Failed to install EIC package on instance.")
            instance_exit=1
        else
            # Run the actual tests
            "${TOPDIR}/bin/integration-test/run_test_sweep.sh" -i "${instance_id}" -p "${public_ip}" -k "${private_key}" -u "${osuser}" -z "${zone}" -o "${output_directory}/${instance_type}" -l "${distro}" -f "${package_path}"
            test_exit=$?
            if [ "${test_exit}" -ne 0 ] ; then
                overall_exit=1
            else
                rmdir "${output_directory}/${instance_type}"
            fi
        fi
        # Terminate the instance
        aws ec2 terminate-instances --instance-ids "${instance_id}" 1>/dev/null
    fi
    if [ "${instance_exit}" -ne 0 ] ; then
        echo "Could not run tests on instance."
        echo "${output}" > "${output_directory}/${instance_type}/setup"
        overall_exit=1
    fi
done

if [ "${overall_exit}" -ne 0 ] ; then
    echo "Some instance types failed.  Please check the contents of ${output_directory} for details."
else
    echo "All instance types passed!  Removing failed output directory since it is empty."
    rmdir "${output_directory}"
fi

exit "${overall_exit}"
