#!/bin/bash

set -eux
set -o pipefail

SCRIPT_NAME=$(basename $0)

OS_AUTH_URL=${OS_AUTH_URL:-""}
if [ -z "$OS_AUTH_URL" ]; then
    echo "You must source a stackrc file for the Undercloud."
    exit 1
fi

TUSKAR=

function show_options () {
    echo "Usage: $SCRIPT_NAME [options]"
    echo
    echo "Deploys an Overcloud."
    echo
    echo "Options:"
    echo "      --tuskar       -- will use tuskar for building the heat Template"
    echo
    exit $1
}

TEMP=$(getopt -o ,h -l,tuskar,help -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
        --tuskar) TUSKAR="1"; shift 1;;
        -h | --help) show_options 0;;
        --) shift ; break ;;
        *) echo "Error: unsupported option $1." ; exit 1 ;;
    esac
done

# setup-baremetal requires this to be set
export TRIPLEO_ROOT=.
export INSTACK_ROOT=${INSTACK_ROOT:-"/usr/share"}
export NODES_JSON=${NODES_JSON:-"instackenv.json"}
export USE_IRONIC=1
export ROOT_DISK=${ROOT_DISK:-10}

register-nodes --service-host undercloud --nodes <(jq '.nodes' $NODES_JSON)

# Must wait for baremetal nodes to register as nova hypervisors
expected_nodes=$(jq ".nodes | length" $NODES_JSON)
expected_memory=$(jq ".nodes | map(.memory | tonumber) | add" $NODES_JSON)
expected_vcpus=$(jq ".nodes | map(.cpu | tonumber) | add" $NODES_JSON)
tripleo wait_for 180 1 wait_for_hypervisor_stats $expected_nodes $expected_memory  $expected_vcpus

tripleo setup-overcloud-passwords -o tripleo-overcloud-passwords
source tripleo-overcloud-passwords

# Undercloud passwords must all be sourced into this script since we make use
# of $UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD below
source tripleo-undercloud-passwords

# Define the interface that will be bridged onto the Neutron defined
# network.
NeutronPublicInterface=${NeutronPublicInterface:-eth0}
HypervisorNeutronPublicInterface=${HypervisorNeutronPublicInterface:-$NeutronPublicInterface}
NEUTRON_NETWORK_TYPE=${NEUTRON_NETWORK_TYPE:-gre}
# Define the overcloud libvirt type for virtualization. kvm for
# baremetal, qemu for an overcloud running in vm's.
OVERCLOUD_LIBVIRT_TYPE=${OVERCLOUD_LIBVIRT_TYPE:-qemu}
NtpServer=${NtpServer:-""}
OVERCLOUD_EXTRA_CONFIG=${OVERCLOUD_EXTRA_CONFIG:-"{}"}

CONTROLSCALE=${CONTROLSCALE:-1}
COMPUTESCALE=${COMPUTESCALE:-1}
BLOCKSTORAGESCALE=${BLOCKSTORAGESCALE:-1}
SWIFTSTORAGESCALE=${SWIFTSTORAGESCALE:-1}

# Default flavor parameters
export OVERCLOUD_CONTROL_FLAVOR=${OVERCLOUD_CONTROL_FLAVOR:-"baremetal"}
export OVERCLOUD_COMPUTE_FLAVOR=${OVERCLOUD_COMPUTE_FLAVOR:-"baremetal"}
export OVERCLOUD_BLOCKSTORAGE_FLAVOR=${OVERCLOUD_BLOCKSTORAGE_FLAVOR:-"baremetal"}
export OVERCLOUD_SWIFTSTORAGE_FLAVOR=${OVERCLOUD_SWIFTSTORAGE_FLAVOR:-"baremetal"}

NeutronControlPlaneID=$(neutron net-show ctlplane | grep ' id ' | awk '{print $4}')

if [ -n "$TUSKAR" ]; then
    PLAN_ID=$( tuskar plan-show overcloud | awk '$2=="uuid" {print $4}' )

    export TUSKAR_PARAMETERS=${TUSKAR_PARAMETERS:-"
    -A NeutronControlPlaneID=${NeutronControlPlaneID}
    -A controller-1::AdminPassword=${OVERCLOUD_ADMIN_PASSWORD}
    -A controller-1::AdminToken=${OVERCLOUD_ADMIN_TOKEN}
    -A cinder-storage-1::AdminPassword=${OVERCLOUD_ADMIN_PASSWORD}
    -A compute-1::AdminPassword=${OVERCLOUD_ADMIN_PASSWORD}
    -A controller-1::SnmpdReadonlyUserPassword=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD}
    -A cinder-storage-1::SnmpdReadonlyUserPassword=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD}
    -A swift-storage-1::SnmpdReadonlyUserPassword=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD}
    -A compute-1::SnmpdReadonlyUserPassword=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD}
    -A controller-1::CeilometerPassword=${OVERCLOUD_CEILOMETER_PASSWORD}
    -A controller-1::CeilometerMeteringSecret=${OVERCLOUD_CEILOMETER_SECRET}
    -A compute-1::CeilometerPassword=${OVERCLOUD_CEILOMETER_PASSWORD}
    -A compute-1::CeilometerMeteringSecret=${OVERCLOUD_CEILOMETER_SECRET}
    -A controller-1::CinderPassword=${OVERCLOUD_CINDER_PASSWORD}
    -A cinder-storage-1::CinderPassword=${OVERCLOUD_CINDER_PASSWORD}
    -A controller-1::GlancePassword=${OVERCLOUD_GLANCE_PASSWORD}
    -A controller-1::HeatPassword=${OVERCLOUD_HEAT_PASSWORD}
    -A controller-1::NeutronPassword=${OVERCLOUD_NEUTRON_PASSWORD}
    -A compute-1::NeutronPassword=${OVERCLOUD_NEUTRON_PASSWORD}
    -A controller-1::NovaPassword=${OVERCLOUD_NOVA_PASSWORD}
    -A compute-1::NovaPassword=${OVERCLOUD_NOVA_PASSWORD}
    -A controller-1::SwiftHashSuffix=${OVERCLOUD_SWIFT_HASH}
    -A controller-1::SwiftPassword=${OVERCLOUD_SWIFT_PASSWORD}
    -A controller-1::CinderISCSIHelper=lioadm
    -A cinder-storage-1::CinderISCSIHelper=lioadm
    -A controller-1::CloudName=overcloud
    -A controller-1::NeutronPublicInterface=$NeutronPublicInterface
    -A compute-1::NeutronPublicInterface=$NeutronPublicInterface
    -A compute-1::NovaComputeLibvirtType=$OVERCLOUD_LIBVIRT_TYPE
    -A controller-1::NtpServer=${NtpServer}
    -A compute-1::NtpServer=${NtpServer}
    -A controller-1::NeutronNetworkType=${NEUTRON_NETWORK_TYPE}
    -A compute-1::NeutronNetworkType=${NEUTRON_NETWORK_TYPE}
    -A swift-storage-1::NeutronNetworkType=${NEUTRON_NETWORK_TYPE}
    -A controller-1::NeutronTunnelTypes=${NEUTRON_TUNNEL_TYPES}
    -A compute-1::NeutronTunnelTypes=${NEUTRON_TUNNEL_TYPES}
    -A controller-1::count=${CONTROLSCALE}
    -A compute-1::count=${COMPUTESCALE}
    -A swift-storage-1::count=${SWIFTSTORAGESCALE}
    -A cinder-storage-1::count=${BLOCKSTORAGESCALE}
    -A controller-1::ExtraConfig=${OVERCLOUD_EXTRA_CONFIG}
    -A compute-1::ExtraConfig=${OVERCLOUD_EXTRA_CONFIG}
    -A swift-storage-1::ExtraConfig=${OVERCLOUD_EXTRA_CONFIG}
    -A cinder-storage-1::ExtraConfig=${OVERCLOUD_EXTRA_CONFIG}
    "}

    if [ $CONTROLSCALE -gt 1 ]; then
        export TUSKAR_PARAMETERS="$TUSKAR_PARAMETERS
        -A controller-1::NeutronL3HA=True
        -A compute-1::NeutronL3HA=True
        "
    fi

    # These attributes can't be changed in Tuskar-UI, so this is the only
    # difference to deploying through UI
    # -A NeutronDnsmasqOptions=dhcp-option-force=26,1400
    # -A NeutronNetworkType=${NEUTRON_NETWORK_TYPE}
    # -A NeutronTunnelTypes=${NEUTRON_TUNNEL_TYPES}

    tuskar plan-patch $TUSKAR_PARAMETERS $PLAN_ID

    # Generate keystone certificates
    HEAT_ENV=${HEAT_ENV:-"overcloud-env.json"}
    ENV_JSON='{"parameters":{}}'

    jq . > "${HEAT_ENV}" <<< $ENV_JSON
    chmod 0600 "${HEAT_ENV}"
    generate-keystone-pki --heatenv $HEAT_ENV

    KeystoneCACertificate=$(os-apply-config -m $HEAT_ENV --key parameters.KeystoneCACertificate --type raw)
    KeystoneSigningCertificate=$(os-apply-config -m $HEAT_ENV --key parameters.KeystoneSigningCertificate --type raw)
    KeystoneSigningKey=$(os-apply-config -m $HEAT_ENV --key parameters.KeystoneSigningKey --type raw)

    # Sending the Certificates one by one, otherwise there are problems with escaping
    tuskar plan-patch -A controller-1::KeystoneCACertificate="${KeystoneCACertificate}" $PLAN_ID
    tuskar plan-patch -A controller-1::KeystoneSigningCertificate="${KeystoneSigningCertificate}" $PLAN_ID
    tuskar plan-patch -A controller-1::KeystoneSigningKey="${KeystoneSigningKey}" $PLAN_ID

    # Get templates from tuskar
    tuskar plan-templates -O tuskar_templates $PLAN_ID

    OVERCLOUD_YAML_PATH="tuskar_templates/plan.yaml"
    ENVIROMENT_YAML_PATH="tuskar_templates/environment.yaml"

    heat stack-create -f $OVERCLOUD_YAML_PATH \
        -e $ENVIROMENT_YAML_PATH \
        overcloud

else
    OVERCLOUD_YAML_PATH="$INSTACK_ROOT/openstack-tripleo-heat-templates/overcloud-without-mergepy.yaml"
    RESOURCE_REGISTRY_PATH="$INSTACK_ROOT/openstack-tripleo-heat-templates/overcloud-resource-registry.yaml"

    export OVERCLOUD_PARAMETERS=${OVERCLOUD_PARAMETERS:-"\
    -P AdminPassword=${OVERCLOUD_ADMIN_PASSWORD} \
    -P AdminToken=${OVERCLOUD_ADMIN_TOKEN} \
    -P CeilometerPassword=${OVERCLOUD_CEILOMETER_PASSWORD} \
    -P CeilometerMeteringSecret=${OVERCLOUD_CEILOMETER_SECRET} \
    -P CinderPassword=${OVERCLOUD_CINDER_PASSWORD} \
    -P CinderISCSIHelper=lioadm \
    -P CloudName=overcloud \
    -P ExtraConfig=${OVERCLOUD_EXTRA_CONFIG} \
    -P GlancePassword=${OVERCLOUD_GLANCE_PASSWORD} \
    -P HeatPassword=${OVERCLOUD_HEAT_PASSWORD} \
    -P NeutronControlPlaneID=$NeutronControlPlaneID \
    -P NeutronDnsmasqOptions=dhcp-option-force=26,1400 \
    -P NeutronPassword=${OVERCLOUD_NEUTRON_PASSWORD} \
    -P NeutronPublicInterface=$NeutronPublicInterface \
    -P HypervisorNeutronPublicInterface=$HypervisorNeutronPublicInterface \
    -P NovaComputeLibvirtType=$OVERCLOUD_LIBVIRT_TYPE \
    -P NovaPassword=${OVERCLOUD_NOVA_PASSWORD} \
    -P SwiftHashSuffix=${OVERCLOUD_SWIFT_HASH} \
    -P SwiftPassword=${OVERCLOUD_SWIFT_PASSWORD} \
    -P NeutronNetworkType=${NEUTRON_NETWORK_TYPE} \
    -P NeutronTunnelTypes=${NEUTRON_TUNNEL_TYPES} \
    -P SnmpdReadonlyUserPassword=${UNDERCLOUD_CEILOMETER_SNMPD_PASSWORD} \
    -P OvercloudControlFlavor=${OVERCLOUD_CONTROL_FLAVOR} \
    -P OvercloudComputeFlavor=${OVERCLOUD_COMPUTE_FLAVOR} \
    -P OvercloudBlockStorageFlavor=${OVERCLOUD_BLOCKSTORAGE_FLAVOR} \
    -P OvercloudSwiftStorageFlavor=${OVERCLOUD_SWIFTSTORAGE_FLAVOR} \
    -P NtpServer=${NtpServer} \
    "}


    if [ $CONTROLSCALE -gt 1 ]; then
        export OVERCLOUD_PARAMETERS="$OVERCLOUD_PARAMETERS \
        -P NeutronL3HA=True \
        "
    fi

    HEAT_ENV=${HEAT_ENV:-"overcloud-env.json"}
    ENV_JSON='{"parameters":{}}'


    RESOURCE_REGISTRY="-e $RESOURCE_REGISTRY_PATH"
    ENV_JSON=$(jq '.parameters = .parameters + {
        "ControllerCount": '${CONTROLSCALE}',
        "ComputeCount": '${COMPUTESCALE}',
        "BlockStorageCount": '${BLOCKSTORAGESCALE}',
        "ObjectStorageCount": '${SWIFTSTORAGESCALE}'
      }' <<< $ENV_JSON)

    jq . > "${HEAT_ENV}" <<< $ENV_JSON
    chmod 0600 "${HEAT_ENV}"
    generate-keystone-pki --heatenv $HEAT_ENV
    HEAT_ENVIRONMENT="-e ${HEAT_ENV}"


    heat stack-create -f $OVERCLOUD_YAML_PATH \
        $RESOURCE_REGISTRY \
        $OVERCLOUD_PARAMETERS \
        $HEAT_ENVIRONMENT \
        overcloud
fi

tripleo wait_for_stack_ready 220 10 overcloud

echo "Overcloud CREATE_COMPLETE"

if [ -d /etc/tripleo ]; then
    TRIPLEO_ROOT=/etc/tripleo
else
    TRIPLEO_ROOT=$INSTACK_ROOT/tripleo-incubator
fi

OVERCLOUD_ENDPOINT=$(heat output-show overcloud KeystoneURL|sed 's/^"\(.*\)"$/\1/')
export OVERCLOUD_IP=$(echo $OVERCLOUD_ENDPOINT | awk -F '[/:]' '{print $4}')

touch ~/.ssh/known_hosts
chmod 600 ~/.ssh/known_hosts
ssh-keygen -R $OVERCLOUD_IP

export no_proxy=${no_proxy:-""}
export no_proxy=$no_proxy,$OVERCLOUD_IP

NEW_JSON=$(jq '.overcloud.password="'${OVERCLOUD_ADMIN_PASSWORD}'" | .overcloud.endpoint="'${OVERCLOUD_ENDPOINT}'" | .overcloud.endpointhost="'${OVERCLOUD_IP}'"' $NODES_JSON)

echo $NEW_JSON > $NODES_JSON

export TE_DATAFILE=$NODES_JSON
source $TRIPLEO_ROOT/overcloudrc

init-keystone -o $OVERCLOUD_IP -t $OVERCLOUD_ADMIN_TOKEN \
-e admin.example.com -p $OVERCLOUD_ADMIN_PASSWORD -u heat-admin \
${SSLBASE:+-s $PUBLIC_API_URL}

# REGISTER_SERVICE_OPTS="--ceilometer-password $OVERCLOUD_CEILOMETER_PASSWORD "
REGISTER_SERVICE_OPTS=""

keystone role-create --name=swiftoperator
keystone role-create --name=ResellerAdmin

tripleo setup-endpoints $OVERCLOUD_IP \
    --cinder-password $OVERCLOUD_CINDER_PASSWORD \
    --glance-password $OVERCLOUD_GLANCE_PASSWORD \
    --heat-password $OVERCLOUD_HEAT_PASSWORD \
    --neutron-password $OVERCLOUD_NEUTRON_PASSWORD \
    --nova-password $OVERCLOUD_NOVA_PASSWORD \
    --swift-password $OVERCLOUD_SWIFT_PASSWORD \
    $REGISTER_SERVICE_OPTS \
    ${SSLBASE:+--ssl $PUBLIC_API_URL}
keystone role-create --name heat_stack_user
# setup-neutron "" "" 10.0.0.0/8 "" "" "" "" 192.0.2.45 192.0.2.64 192.0.2.0/24
NETWORK_CIDR=${NETWORK_CIDR:-"10.0.0.0/8"}
FLOATING_IP_START=${FLOATING_IP_START:-"172.17.0.45"}
FLOATING_IP_END=${FLOATING_IP_END:-"172.17.0.64"}
FLOATING_IP_CIDR=${FLOATING_IP_CIDR:-"172.17.0.0/16"}
OVERCLOUD_NAMESERVER="8.8.8.8"
BM_NETWORK_GATEWAY=${BM_NETWORK_GATEWAY:-"172.17.0.1"}

NETWORK_JSON=$(mktemp)
jq "." <<EOF > $NETWORK_JSON
{
    "float": {
        "cidr": "$NETWORK_CIDR",
        "name": "default-net",
        "nameserver": "$OVERCLOUD_NAMESERVER"
    },
    "external": {
        "name": "ext-net",
        "cidr": "$FLOATING_IP_CIDR",
        "allocation_start": "$FLOATING_IP_START",
        "allocation_end": "$FLOATING_IP_END",
        "gateway": "$BM_NETWORK_GATEWAY"
    }
}
EOF

setup-neutron -n $NETWORK_JSON
rm $NETWORK_JSON


nova flavor-create m1.demo auto 512 10 1

echo "Overcloud Deployed"
