#!/bin/bash
#
# Description:
#   Helper functions to programmatically provision (e.g. for CIT).
#   Aliases on these functions are also created so that this script can be
#   sourced in your shell, in your ~/.bashrc file, etc. and directly called.
#
# Usage:
#   Source this file and call the relevant functions.
#

function ssh_public_key() {
    echo -e "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDZBgLQts30PYXEMJnCU21QC+1ZE0Sv/Ry48Au3nYXn1KNoW/7C2qQ3KO2ZnpZRHCstFiU8QIlB9edi0cgcAoDWBkCiFBZEORxMvohWtrRQzf+x59o48lVjA/Fn7G+9hmavhLaDf6Qe7OhH8XUshNtnIQIUvNEWXKE75k32wUbuF8ibhJNpOOYKL4tVXK6IIKg6jR88BwGKPY/NZCl/HbhjnDJY0zCU1pZSprN6o/S953y/XXVozkh1772fCNeu4USfbt0oZOEJ57j6EWwEYIJhoeAEMAoD8ELt/bc/5iex8cuarM4Uib2JHO6WPWbBQ0NlrARIOKLrxkjjfGWarOLWBAgvwQn5zLg1pKb7aI4+jbA+ZSrII5B2HuYE9MDlU8NPL4pHrRfapGLkG/Fe9zNPvScXh+9iSWfD6G5ZoISutjiJO/iVYN0QSuj9QEIj9tl20czFz3Dhnq4sPPl5hoLunyQfajY7C/ipv6ilJyrEc0V6Z9FdPhpEI+HOgJr2vDQTFscQuyfWuzGJDZf6zPdZWo2pBql9E7piARuNAjakylGar/ebkCgfy28XQoDbDT0P0VYp+E8W5EYacx+zc5MuNhRTvbsO12fydT8V61MtA78wM/b0059feph+0zTykEHk670mYVoE3erZX+U1/BVBLSV9QzopO6/Pgx2ryriJfQ== weaveworks-cit"
}

function decrypt() {
    if [ -z "$1" ]; then
        echo >&2 "Failed to decode and decrypt $2: no secret key was provided."
        return 1
    fi
    # Set md5 because existing keys were encrypted that way and openssl default changed
    echo "$3" | openssl base64 -d | openssl enc -md md5 -d -aes256 -pass "pass:$1"
}

function ssh_private_key() {
    # The private key has been AES256-encrypted and then Base64-encoded using the following command:
    #   $ openssl enc -in /tmp/weaveworks_cit_id_rsa -e -aes256 -pass stdin | openssl base64 > /tmp/weaveworks_cit_id_rsa.aes.b64
    # The below command does the reverse, i.e. base64-decode and AES-decrypt the file, and prints it to stdout.
    # N.B.: Ask the password to Marc, or otherwise re-generate the SSH key using:
    #   $ ssh-keygen -t rsa -b 4096 -C "weaveworks-cit"
    decrypt "$1" "SSH private key" "$(
        cat <<EOF
[encoded data, 4420 characters]
EOF
    )"
}

function set_up_ssh_private_key() {
    if [ -z "$1" ]; then
        echo >&2 "Failed to decode and decrypt SSH private key: no secret key was provided."
        return 1
    fi
    local ssh_private_key_path="$HOME/.ssh/weaveworks_cit_id_rsa"
    [ -e "$ssh_private_key_path" ] && rm -f "$ssh_private_key_path"
    ssh_private_key "$1" >"$ssh_private_key_path"
    chmod 400 "$ssh_private_key_path"
    echo "$ssh_private_key_path"
}

function gcp_credentials() {
    # The below GCP service account JSON credentials have been AES256-encrypted and then Base64-encoded using the following command:
    #   $ openssl enc -in ~/.ssh/weaveworks-cit.json -e -aes256 -pass stdin | openssl base64 > /tmp/weaveworks-cit.json.aes.b64
    # The below command does the reverse, i.e. base64-decode and AES-decrypt the file, and prints it to stdout.
    # N.B.: Ask the password to Marc, or otherwise re-generate the credentials for GCP, as per ../tools/provisioning/gcp/README.md.
    decrypt "$1" "JSON credentials" "$(
        cat <<EOF
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
EOF
    )"
}

# shellcheck disable=2155
function do_on() {
    # Set up everything required to run tests on Digital Ocean.
    # Steps from ../tools/provisioning/do/README.md have been followed.
    # All sensitive files have been encrypted, see respective functions.
    if [ -z "$SECRET_KEY" ]; then
        echo >&2 "Failed to configure for Digital Ocean: no value for the SECRET_KEY environment variable."
        return 1
    fi

    # SSH public key:
    export TF_VAR_do_public_key_path="$HOME/.ssh/weaveworks_cit_id_rsa.pub"
    ssh_public_key >"$TF_VAR_do_public_key_path"
    export DIGITALOCEAN_SSH_KEY_NAME="weaveworks-cit"
    export TF_VAR_do_public_key_id=5228799

    # SSH private key:
    export TF_VAR_do_private_key_path=$(set_up_ssh_private_key "$SECRET_KEY")

    # API token:
    # The below Digital Ocean token has been AES256-encrypted and then Base64-encoded using the following command:
    #   $ openssl enc -in /tmp/digital_ocean_token.txt -e -aes256 -pass stdin | openssl base64 > /tmp/digital_ocean_token.txt.aes.b64
    # The below command does the reverse, i.e. base64-decode and AES-decrypt the file, and prints it to stdout.
    # N.B.: Ask the password to Marc, or otherwise re-generate the token for Digital Ocean, as per ../tools/provisioning/do/README.md.
    export DIGITALOCEAN_TOKEN=$(decrypt "$SECRET_KEY" "Digital Ocean token" "U2FsdGVkX1/Gq5Rj9dDDraME8xK30JOyJ9dhfQzPBaaePJHqDPIG6of71DdJW0UyFUyRtbRflCPaZ8Um1pDJpU5LoNWQk4uCApC8+xciltT73uQtttLBG8FqgFBvYIHS")
    export DIGITALOCEAN_TOKEN_NAME="weaveworks-cit"
    export TF_VAR_client_ip=$(curl -s -X GET http://checkip.amazonaws.com/)
}
alias do_on='do_on'

function do_off() {
    unset TF_VAR_do_public_key_path
    unset DIGITALOCEAN_SSH_KEY_NAME
    unset TF_VAR_do_public_key_id
    unset TF_VAR_do_private_key_path
    unset DIGITALOCEAN_TOKEN
    unset DIGITALOCEAN_TOKEN_NAME
    unset TF_VAR_client_ip
}
alias do_off='do_off'

# shellcheck disable=2155
function gcp_on() {
    # Set up everything required to run tests on GCP.
    # Steps from ../tools/provisioning/gcp/README.md have been followed.
    # All sensitive files have been encrypted, see respective functions.
    if [ -z "$SECRET_KEY" ]; then
        echo >&2 "Failed to configure for Google Cloud Platform: no value for the SECRET_KEY environment variable."
        return 1
    fi

    # SSH public key and SSH username:
    export TF_VAR_gcp_public_key_path="$HOME/.ssh/weaveworks_cit_id_rsa.pub"
    ssh_public_key >"$TF_VAR_gcp_public_key_path"
    export TF_VAR_gcp_username=$(cut -d' ' -f3 "$TF_VAR_gcp_public_key_path" | cut -d'@' -f1)

    # SSH private key:
    export TF_VAR_gcp_private_key_path=$(set_up_ssh_private_key "$SECRET_KEY")

    # JSON credentials:
    export GOOGLE_CREDENTIALS_FILE="$HOME/.ssh/weaveworks-cit.json"
    [ -e "$GOOGLE_CREDENTIALS_FILE" ] && rm -f "$GOOGLE_CREDENTIALS_FILE"
    gcp_credentials "$SECRET_KEY" >"$GOOGLE_CREDENTIALS_FILE"
    chmod 400 "$GOOGLE_CREDENTIALS_FILE"
    export GOOGLE_CREDENTIALS=$(cat "$GOOGLE_CREDENTIALS_FILE")

    export TF_VAR_client_ip=$(curl -s -X GET http://checkip.amazonaws.com/)
    export TF_VAR_gcp_project="${PROJECT:-"weave-net-tests"}"
    # shellcheck disable=2015
    [ -z "$PROJECT" ] && echo >&2 "WARNING: no value provided for PROJECT environment variable: defaulted it to $TF_VAR_gcp_project." || true
}
alias gcp_on='gcp_on'

function gcp_off() {
    unset TF_VAR_gcp_public_key_path
    unset TF_VAR_gcp_username
    unset TF_VAR_gcp_private_key_path
    unset GOOGLE_CREDENTIALS_FILE
    unset GOOGLE_CREDENTIALS
    unset TF_VAR_client_ip
    unset TF_VAR_gcp_project
}
alias gcp_off='gcp_off'

# shellcheck disable=2155
function aws_on() {
    # Set up everything required to run tests on Amazon Web Services.
    # Steps from ../tools/provisioning/aws/README.md have been followed.
    # All sensitive files have been encrypted, see respective functions.
    if [ -z "$SECRET_KEY" ]; then
        echo >&2 "Failed to configure for Amazon Web Services: no value for the SECRET_KEY environment variable."
        return 1
    fi

    # SSH public key:
    export TF_VAR_aws_public_key_name="weaveworks_cit_id_rsa"

    # SSH private key:
    export TF_VAR_aws_private_key_path=$(set_up_ssh_private_key "$SECRET_KEY")

    # The below AWS access key ID and secret access key have been AES256-encrypted and then Base64-encoded using the following commands:
    #   $ openssl enc -in /tmp/aws_access_key_id.txt     -e -aes256 -pass stdin | openssl base64 > /tmp/aws_access_key_id.txt.aes.b64
    #   $ openssl enc -in /tmp/aws_secret_access_key.txt -e -aes256 -pass stdin | openssl base64 > /tmp/aws_secret_access_key.txt.aes.b64
    # The below commands do the reverse, i.e. base64-decode and AES-decrypt the encrypted and encoded strings, and print it to stdout.
    # N.B.: Ask the password to Marc, or otherwise re-generate the AWS access key ID and secret access key, as per ../tools/provisioning/aws/README.md.
    export AWS_ACCESS_KEY_ID="$(decrypt "$SECRET_KEY" "AWS access key ID" "U2FsdGVkX18Txjm2PWSlJsToYm1vv4dMTtVLkRNiQbrC6Y6GuIHb1ao5MmGPJ1wf")"
    export AWS_SECRET_ACCESS_KEY="$(decrypt "$SECRET_KEY" "AWS secret access key" "$(
        cat <<EOF
U2FsdGVkX1/BFp/lQnSoy0LxUuDz0z0YnqxhO8KBrtt3x6YEWyVFzY34rFhpGiB7
IxYq20K87Zrx/Q/urMoWgg==
EOF
    )")"

    export TF_VAR_client_ip=$(curl -s -X GET http://checkip.amazonaws.com/)
}
alias aws_on='aws_on'

function aws_off() {
    unset TF_VAR_aws_public_key_name
    unset TF_VAR_aws_private_key_path
    unset AWS_ACCESS_KEY_ID
    unset AWS_SECRET_ACCESS_KEY
    unset TF_VAR_client_ip
}
alias aws_off='aws_off'

function tf_ssh_usage() {
    cat >&2 <<-EOF
ERROR: $1

Usage:
  \$ tf_ssh <host ID (1-based)> [OPTION]...
Examples:
  \$ tf_ssh 1
  \$ tf_ssh 1 -o LogLevel VERBOSE
  \$ tf_ssh 1 -i ~/.ssh/custom_private_key_id_rsa
Available machines:
EOF
    cat -n >&2 <<<"$(terraform output public_etc_hosts)"
}

# shellcheck disable=SC2155
function tf_ssh() {
    [ -z "$1" ] && tf_ssh_usage "No host ID provided." && return 1
    local ip="$(sed "$1q;d" <<<"$(terraform output public_etc_hosts)" | cut -d ' ' -f 1)"
    shift # Drop the first argument, corresponding to the machine ID, to allow passing other arguments to SSH using "$@" -- see below.
    [ -z "$ip" ] && tf_ssh_usage "Invalid host ID provided." && return 1
    # shellcheck disable=SC2029
    ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "$@" "$(terraform output username)@$ip"
}
alias tf_ssh='tf_ssh'

function tf_ansi_usage() {
    cat >&2 <<-EOF
ERROR: $1

Usage:
  \$ tf_ansi <playbook or playbook ID (1-based)> [OPTION]...
Examples:
  \$ tf_ansi setup_weave-net_dev
  \$ tf_ansi 1
  \$ tf_ansi 1 -vvv --private-key=~/.ssh/custom_private_key_id_rsa
  \$ tf_ansi setup_weave-kube --extra-vars "docker_version=1.12.6 kubernetes_version=1.5.6"
Available playbooks:
EOF
    cat -n >&2 <<<"$(for file in "$(dirname "${BASH_SOURCE[0]}")"/../../config_management/*.yml; do basename "$file" | sed 's/.yml//'; done)"
}

# shellcheck disable=SC2155,SC2064
function tf_ansi() {
    [ -z "$1" ] && tf_ansi_usage "No Ansible playbook provided." && return 1
    local id="$1"
    shift # Drop the first argument to allow passing other arguments to Ansible using "$@" -- see below.
    if [[ "$id" =~ ^[0-9]+$ ]]; then
        local playbooks=(../../config_management/*.yml)
        local path="${playbooks[(($id - 1))]}" # Select the ith entry in the list of playbooks (0-based).
    else
        local path="$(dirname "${BASH_SOURCE[0]}")/../../config_management/$id.yml"
    fi
    local inventory="$(mktemp /tmp/ansible_inventory_XXX)"
    trap 'rm -f $inventory' SIGINT SIGTERM RETURN
    echo -e "$(terraform output ansible_inventory)" >"$inventory"
    [ ! -r "$path" ] && tf_ansi_usage "Ansible playbook not found: $path" && return 1
    ansible-playbook "$@" -u "$(terraform output username)" -i "$inventory" --ssh-extra-args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" "$path"
}
alias tf_ansi='tf_ansi'
