#!/bin/sh

set -e
#set -x

. /root/oci-openrc

DEBIAN_RELEASE=$(lsb_release -c -s)
DEBIAN_RELEASE_NUM=$(lsb_release -r -s)
DEBIAN_ARCH=$(dpkg-architecture -q DEB_BUILD_ARCH)
IMAGE_NAME=debian-${DEBIAN_RELEASE_NUM}-generic-${DEBIAN_ARCH}.qcow2
IMAGE_URL=http://cdimage.debian.org/cdimage/cloud/${DEBIAN_RELEASE}/latest/${IMAGE_NAME}
IMAGE_DOWNLOAD_TIMEOUT=30

####################
### GLANCE IMAGE ###
####################
oci_poc_prov_cloud_glance_image () {
	echo "===> Provisioning of a Glance image"
	if ! [ -f /root/${IMAGE_NAME} ] ; then
		echo "---> Fetching image from ${IMAGE_URL}"
		if [ -e /etc/oci/http_proxy_addr ] ; then
			http_proxy_addr=$(cat /etc/oci/http_proxy_addr)
			http_proxy=${http_proxy_addr} timeout ${IMAGE_DOWNLOAD_TIMEOUT} wget ${IMAGE_URL}
		else
			timeout ${IMAGE_DOWNLOAD_TIMEOUT} wget ${IMAGE_URL}
		fi
	else
		echo "---> Image already saved in /root"
	fi

	if [ -z "${IMAGE_NAME}" ] ; then
		echo "Cannot find image to upload to Glance"
		exit 1
	fi
	if echo "${IMAGE_NAME}" | grep -q qcow2 ; then
		DISK_FORMAT=qcow2
	else
		DISK_FORMAT=raw
	fi

	echo "---> Fetching image list"
	IMAGE_ID=$(openstack image list --property os_distro=debian --format value -c ID)

	if [ -z "${IMAGE_ID}" ] ; then
		echo "---> Uploading image to OpenStack"
		openstack image create \
			--property hw_disk_bus=scsi \
			--property hw_scsi_model=virtio-scsi \
			--container-format bare --disk-format ${DISK_FORMAT} \
			--property os_distro=debian \
			--file /root/${IMAGE_NAME} \
			--public \
			${IMAGE_NAME}
	fi
}

#########################
### Enable nova hosts ###
#########################
oci_poc_prov_cloud_enable_all_compute_hosts () {
	echo "===> Enabling compute"
	echo "---> Discovering compute hosts"
	su nova -s /bin/sh -c 'nova-manage cell_v2 discover_hosts'

	for host in $(openstack compute service list --format csv | q -H -d, "SELECT Host FROM - WHERE Binary='nova-compute'") ; do
		echo "---> Enabling $host"
		openstack compute service set --enable $host nova-compute
	done
}

##################
### NETWORKING ###
##################
oci_poc_prov_cloud_create_networks () {
	echo "===> Provisionning network"
	EXT_NETWORK_PREFIX=192.168.105
	INT_NETWORK_PREFIX=192.168.200

	# Create external network
	echo "---> Listing networks"
	EXT_NETWORK_ID=$(openstack network list --name ext-net --format value -c ID)
	if [ -z "${EXT_NETWORK_ID}" ] ; then
		echo "---> Creating ext-net"
		openstack network create --external \
			--provider-physical-network external --provider-network-type flat \
			ext-net
	fi
	echo "---> Listing subnets"
	EXT_SUBNET_ID=$(openstack subnet list --name ext-subnet --format value -c ID)
	if [ -z "${EXT_SUBNET_ID}" ] ; then
		echo "---> Creating ext-subnet"
		openstack subnet create --network ext-net \
			--allocation-pool start=${EXT_NETWORK_PREFIX}.100,end=${EXT_NETWORK_PREFIX}.199 \
			--gateway ${EXT_NETWORK_PREFIX}.1 --subnet-range ${EXT_NETWORK_PREFIX}.0/24 \
			--dns-nameserver 84.16.67.69 \
			--no-dhcp \
			ext-subnet
	fi

	# Create internal network
	echo "---> Listing networks"
	INT_NETWORK_ID=$(openstack network list --name demo-net --format value -c ID)
	if [ -z "${INT_NETWORK_ID}" ] ; then
		echo "---> Creating demo-net"
		openstack network create --share demo-net
	fi
	echo "---> Fetching demo-subnet ID"
	INT_SUBNET_ID=$(openstack subnet list --name demo-subnet --format value -c ID)
	if [ -z "${INT_SUBNET_ID}" ] ; then
		echo "---> Creating demo subnet"
		openstack subnet create --network demo-net \
			--subnet-range ${INT_NETWORK_PREFIX}.0/24 --dns-nameserver 84.16.67.69 \
			demo-subnet
		echo "---> Fetching demo-subnet ID"
		INT_SUBNET_ID=$(openstack subnet list --name demo-subnet --format value -c ID)
	fi

	# Create router, add it to demo-subnet and set it as gateway
	echo "---> Listing routers"
	ROUTER_ID=$(openstack router list --name demo-router --format value -c ID)
	if [ -z "${ROUTER_ID}" ] ; then
		echo "---> Creating demo-router"
		openstack router create demo-router
	fi
	echo "---> Checking external gateway info"
	EXT_GW=$(openstack router show demo-router --format value -c external_gateway_info)
	if [ "${EXT_GW}" = "None" ] ; then
		echo "---> Setting-up external gateway"
		openstack router set demo-router --external-gateway ext-net
	fi
	echo "---> Checking subnet on router"
	if ! openstack router show demo-router --format json -c interfaces_info | jq -r '.["interfaces_info"][]["subnet_id"]' | grep -q -E "^${INT_SUBNET_ID}\$" ; then
		echo "---> Adding subnet on router"
		openstack router add subnet demo-router demo-subnet
	fi

	# Create up to 5 floating IPs
	echo "---> Listing floating IPs"
	NUM_FLOAT=$(openstack floating ip list --network ext-net --format value -c ID | wc -l)
	while [ "${NUM_FLOAT}" -lt 5 ] ; do
		echo "---> Creating floating IP"
		openstack floating ip create ext-net
		echo "---> Listing floating IPs"
		NUM_FLOAT=$(openstack floating ip list --network ext-net --format value -c ID | wc -l)
	done
}

oci_poc_prov_cloud_security_group () {
	echo "===> Settting-up default security group to allow ICMP and SSH"
	# Add rules to the admin's security group to allow ping and ssh
	echo "---> Fetching security group ID"
	SECURITY_GROUP=$(openstack security group list --project admin --format=csv | q -d , -H 'SELECT ID FROM -')
	echo "---> Checking if SSH rule exists"
	if ! openstack security group rule list --ingress --protocol tcp --format value -c 'Port Range' ${SECURITY_GROUP} | grep -q -E "^22:22\$" ; then
		echo "---> Creating SSH rule"
		openstack security group rule create --ingress --protocol tcp --dst-port 22 ${SECURITY_GROUP}
	fi
	echo "---> Checking if ICMP rule exists"
	ICMP_RULE_ID=$(openstack security group rule list --ingress --protocol icmp --format value -c ID ${SECURITY_GROUP})
	if [ -z "${ICMP_RULE_ID}" ] ; then
		echo "---> Creating ICMP rule"
		openstack security group rule create --protocol icmp --ingress ${SECURITY_GROUP}
	fi
}

###############
### SSH KEY ###
###############
oci_poc_prov_cloud_keypair () {
	echo "===> Creating keypair"
	echo "---> Checking if keypair exists"
	if ! openstack keypair list --format value -c Name | grep -q -E "^demo-keypair\$" ; then
		echo "---> Creating keypair"
		openstack keypair create --public-key ~/.ssh/id_rsa.pub demo-keypair
	fi
}

###############
### FLAVORS ###
###############
oci_poc_prov_cloud_flavors () {
	echo "===> Creating flavors"
	for F in cpu1-ram2-disk5 cpu2-ram6-disk20 cpu4-ram12-disk40 ; do
		echo "---> Checking for $F"
		if ! openstack flavor list --format value -c Name | grep -q -E "^${F}\$" ; then
			CPU=$(echo ${F} | cut -d- -f1 | sed s/cpu//)
			RAM=$(( $(echo ${F} | cut -d- -f2 | sed s/ram//) * 1024 ))
			DISK=$(echo ${F} | cut -d- -f3 | sed s/disk//)
			echo "---> Creating $F"
			openstack flavor create --ram ${RAM} --disk ${DISK} --vcpus ${CPU} ${F}
		fi
	done
}

###################
### Spawn 2 VMs ###
###################
oci_poc_prov_cloud_create_server () {
	local SERVER_NAME
	SERVER_NAME=$1
	echo "===> Spawning server ${SERVER_NAME}"
	echo "---> Searching Debian image"
	OPENSTACK_IMAGE=$(openstack image list --property os_distro=debian --format value -c Name --public | head -n 1)

	echo "---> Checking if server exists"
	SERVER_ID=$(openstack server show ${SERVER_NAME} --format value -c id || true)
	if [ -z "${SERVER_ID}" ] ; then
		echo "---> Spawning server"
		openstack server create --image ${OPENSTACK_IMAGE} --nic net-id=demo-net --key-name demo-keypair --flavor cpu1-ram2-disk5 ${SERVER_NAME}
	else
		echo "---> Already spawned"
	fi
}

oci_poc_prov_cloud_wait_for_server_status () {
	local SERVER_NAME SERVER_STATUS TIMEOUT
	SERVER_NAME=$1
	SERVER_TARGET_STATUS=$2
	TIMEOUT=$3

	START_TIMESTAMP=$(date +%s)

	echo -n "Waiting for ${SERVER_NAME} status ${SERVER_TARGET_STATUS}:"
	SERVER_STATUS=$(openstack server show ${SERVER_NAME} --format value -c status)
	while [ "${SERVER_STATUS}" != "${SERVER_TARGET_STATUS}" ] ; do
		if [ "${STATUS}" = "ERROR" ] ; then
			echo "Server went into error: exiting."
			exit 1
		fi
		sleep 2
		CUR__TIMESTAMP=$(date +%s)
		RUNTIME=$(( ${START_TIMESTAMP} - ${CUR__TIMESTAMP} ))
		if [ ${RUNTIME} -gt ${TIMEOUT} ] ; then
			echo "Timeout waiting for server status."
			exit 1
		fi

		SERVER_STATUS=$(openstack server show ${SERVER_NAME} --format value -c status)
		echo -n "."
	done
	echo "Ok."

}

# openstack server add floating ip
oci_poc_prov_cloud_add_floating_to_server () {
	local SERVER_NAME
	SERVER_NAME=$1

	echo "===> Adding floating IP to ${SERVER_NAME}"
	echo "---> Checking if server already has a floating"
	if ! openstack server show --format value -c addresses demo-server-1 | grep -q ',' ; then
		echo "---> Fetching the first available floating IP"
		FLOATING_UUID=$(openstack floating ip list --status DOWN --format value -c ID | head -n 1)
		echo "---> Adding it to ${SERVER_NAME}"
		openstack server add floating ip ${SERVER_NAME} ${FLOATING_UUID}
	fi
}

oci_poc_prov_cloud_glance_image
oci_poc_prov_cloud_enable_all_compute_hosts
oci_poc_prov_cloud_create_networks
oci_poc_prov_cloud_security_group
oci_poc_prov_cloud_keypair
oci_poc_prov_cloud_flavors
oci_poc_prov_cloud_create_server demo-server-1
oci_poc_prov_cloud_create_server demo-server-2
oci_poc_prov_cloud_wait_for_server_status demo-server-1 ACTIVE 30
oci_poc_prov_cloud_wait_for_server_status demo-server-2 ACTIVE 30
oci_poc_prov_cloud_add_floating_to_server demo-server-1

exit 0
