#!/bin/sh

set -e

export PKGOS_VERBOSE=yes

. /usr/share/openstack-pkg-tools/pkgos_func

DO_EXIT=no
for i in $@ ; do
	case "${1}" in
	"--ext-host-min")
		if [ -z "${2}" ] ; then echo "Parameter for option --ext-host-min is missing" > /dev/stderr ; DO_EXIT="yes" ; fi
		EXT_HOST_MIN=$2
		shift
		shift
	;;
	"--ext-host-max")
		if [ -z "${2}" ] ; then echo "Parameter for option --ext-host-max is missing" > /dev/stderr ; DO_EXIT="yes" ; fi
		EXT_HOST_MAX=$2
		shift
		shift
	;;
	"--mgmt-ip-cidr")
		if [ -z "${2}" ] ; then echo "Parameter for option --mgmt-ip-cidr is missing" > /dev/stderr ; DO_EXIT="yes" ; fi
		MGMT_IP_CIDR=$2
		shift
		shift
	;;
	"--mgmt-if")
		if [ -z "${2}" ] ; then echo "Parameter for option --mgmt-if is missing" > /dev/stderr ; DO_EXIT="yes" ; fi
		MGMT_IF=$2
		shift
		shift
	;;
	"--local-ip")
		if [ -z "${2}" ] ; then echo "Parameter for option --mgmt-if is missing" > /dev/stderr ; DO_EXIT="yes" ; fi
		LOCAL_IP=$2
		shift
		shift
	;;
	esac
done


if [ "${DO_EXIT}" = "yes" ] ; then
	echo "Parameters not validated: will exit now!" > /dev/stderr
	exit 1
fi


prompt_for_mgmt_network () {
	if [ -z "${MGMT_IP_CIDR}" ] ; then
		echo -n "Please enter the IP of your management network [172.16.99.1/24]:"
		read MGMT_IP_CIDR
	fi
	if [ -z "${MGMT_IP_CIDR}" ] ; then
		MGMT_IP_CIDR=172.16.99.1/24
	fi
	MGMT_NET_CIDR=`ipcalc ${MGMT_IP_CIDR} | grep Network: | awk '{print $2}'`
	MGMT_NET=`echo ${MGMT_NET_CIDR} | cut -d'/' -f1`
	MGMT_IP=`echo ${MGMT_IP_CIDR} | cut -d'/' -f1`
	MGMT_MASK=`ipcalc ${MGMT_IP_CIDR} | grep Netmask: | awk '{print $2}'`
	if [ -z "${MGMT_IF}" ] ; then
		echo -n "Please enter the interface name for your MGNT net [eth1]:"
		read MGMT_IF
	fi
	if [ -z "${MGMT_IF}" ] ; then
		MGMT_IF=eth1
	fi
}

find_default_ip () {
	local DEFROUTE_IF
	apt-get install -y python-q-text-as-data
	if [ -r /etc/default/openstack-proxy-node-network ] ; then
		echo "===> Loading default IP configuration from /etc/default/openstack-proxy-node-network"
		. /etc/default/openstack-proxy-node-network
	else
		echo "===> Detecting current IP configuration"
		DEFROUTE_IF=`LC_ALL=C /sbin/route | grep default |awk -- '{ print $8 }' | cut -d" " -f1`
		if [ -n "${DEFROUTE_IF}" ] ; then
			DEFROUTE_IP=`LC_ALL=C ip addr show "${DEFROUTE_IF}" | grep inet | head -n 1 | awk '{print $2}' | cut -d/ -f1 | grep -E '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'`
			if [ -n ${DEFROUTE_IP} ] ; then
				DEFROUTE_IP_CIDR=`LC_ALL=C ip addr show ${DEFROUTE_IF} | grep inet | head -n 1 | awk '{print $2}'`
				DEFROUTE_MASK=`ipcalc ${DEFROUTE_IP_CIDR} | grep Netmask: | awk '{print $2}'`
				DEFROUTE_GW=`LC_ALL=C /sbin/route -n | awk 'NR > 1 {print}' | q -H "SELECT Gateway FROM - WHERE Destination='0.0.0.0'"`
				echo "===> Founded the following network config: ${DEFROUTE_IP} netmask: ${DEFROUTE_MASK} gateway ${DEFROUTE_GW}"
				echo "===> Writing it in /etc/default/openstack-proxy-node-network"
				echo "# This file is used by /etc/init.d/openstack-proxy-node-network
# to setup networking at boot time. The goal of this script is to
# setup networking correctly in order to use tempest tests in a VM.
#
# So please do not report about correctness and policy compliance
# if you aren't providing patches to improve. It's OK if it is a bit
# hackish, the goal is just to run functional tempest tests

DEFROUTE_IP=${DEFROUTE_IP}
DEFROUTE_MASK=${DEFROUTE_MASK}
DEFROUTE_GW=${DEFROUTE_GW}
DEFROUTE_IP_CIDR=${DEFROUTE_IP_CIDR}

MGMT_IF=${MGMT_IF}

MGMT_NET=${MGMT_NET}
MGMT_NET_CIDR=${MGMT_NET_CIDR}
MGMT_IP=${MGMT_IP}
MGMT_MASK=${MGMT_MASK}
MGMT_IP_CIDR=${MGMT_IP_CIDR}

TENANT_NET=192.168.100.0
TENANT_NET_CIDR=192.168.100.0/24
" > /etc/default/openstack-proxy-node-network
			else
				echo "Could not find your default route IP address: exiting"
				exit 1
			fi
		fi
		. /etc/default/openstack-proxy-node-network
	fi
}

install_and_start_network_init_script () {
	IS_SYSTEMD=no
	if [ -r /proc/1/comm ] ; then
		if [ `cat /proc/1/comm` = "systemd" ] ; then
			IS_SYSTEMD=yes
		fi
	fi
	echo "===> Installing OVS bridged network init script"
	cp /usr/share/openstack-deploy/openstack-proxy-node-network /etc/init.d
	chmod +x /etc/init.d/openstack-proxy-node-network
	update-rc.d openstack-proxy-node-network defaults
	echo "===> Starting OVS bridged network init script"
	if [ "${IS_SYSTEMD}" = "yes" ] ; then
		nohup /etc/init.d/openstack-proxy-node-network systemd-start
	else
		nohup invoke-rc.d openstack-proxy-node-network start
	fi

	echo "===> Installing MGMT network NAT init script"
	cp /usr/share/openstack-deploy/openstack-proxy-node-nat /etc/init.d
	chmod +x /etc/init.d/openstack-proxy-node-nat
	update-rc.d openstack-proxy-node-nat defaults
	echo "===> Starting MGMT network NAT init script"
	if [ "${IS_SYSTEMD}" = "yes" ] ; then
		nohup /etc/init.d/openstack-proxy-node-nat systemd-start
	else
		invoke-rc.d openstack-proxy-node-nat start
	fi
}

pkgos_get_id () {
	SERVICE_ENDPOINT=${SERVICE_ENDPOINT:-http://127.0.0.1:35357/v2.0/} SERVICE_TOKEN=${AUTH_TOKEN} "$@" | awk '/ id / { print $4 }'
}

calc_host_min_max () {
	local DIGIT1 DIGIT2 DIGIT3 DIGIT4
	if [ -z "${EXT_HOST_MAX}" ] ; then
		EXT_HOST_MAX=`ipcalc ${DEFROUTE_IP_CIDR} | grep HostMax: | awk '{print $2}'`
	fi
	if [ -z "${EXT_HOST_MIN}" ] ; then
		DIGIT1=`echo ${DEFROUTE_IP} | cut -d. -f1`
		DIGIT2=`echo ${DEFROUTE_IP} | cut -d. -f2`
		DIGIT3=`echo ${DEFROUTE_IP} | cut -d. -f3`
		DIGIT4=`echo ${DEFROUTE_IP} | cut -d. -f4`
		DIGIT4=$(( ${DIGIT4} + 1))
		EXT_HOST_MIN="${DIGIT1}.${DIGIT2}.${DIGIT3}.${DIGIT4}"
	fi
	EXT_NET_CIDR=`ipcalc ${DEFROUTE_IP_CIDR} | grep Network: | awk '{print $2}'`
}

source_openrc_if_present () {
	if [ -r ~/openrc.sh ] ; then
		. ~/openrc.sh
	fi
}

setup_local_ip () {
	if [ -n "${LOCAL_IP}" ] ; then
		pkgos_inifile set /etc/neutron/plugins/ml2/openvswitch_agent.ini ovs local_ip ${LOCAL_IP}
		if [ -x /etc/init.d/neutron-plugin-openvswitch-agent ] ; then
			invoke-rc.d neutron-plugin-openvswitch-agent restart
		elif [ -x /etc/init.d/neutron-openvswitch-agent ] ; then
			invoke-rc.d neutron-openvswitch-agent restart
		else
			echo "Could not find neutron-openvswitch-agent"
			exit 1
		fi
	fi
}

fix_nova_tenant_id_in_neutron () {
	ADMIN_TENANT_ID=`keystone tenant-get admin | awk '/ id / { print $4 }'`
	pkgos_inifile set /etc/neutron/neutron.conf DEFAULT nova_admin_tenant_id ${ADMIN_TENANT_ID}
}

fix_nova_and_neutron_admin_pass () {
	pkgos_inifile set /etc/nova/nova.conf neutron admin_password ${OS_PASSWORD}
	pkgos_inifile set /etc/neutron/neutron.conf DEFAULT nova_admin_password ${OS_PASSWORD}
}

setup_metadata_shared_secret () {
	GEN_METADATA_SECRET=`pkgos_gen_pass`
	pkgos_inifile set /etc/nova/nova.conf neutron metadata_proxy_shared_secret ${GEN_METADATA_SECRET}
	pkgos_inifile set /etc/neutron/metadata_agent.ini DEFAULT metadata_proxy_shared_secret ${GEN_METADATA_SECRET}
}

misc_system_fix () {
	# Fix /var/run/shm unix rights in case we're on a broken Wheezy system.
	if ! [ -h /var/run/shm ] ; then chmod 777 /var/run/shm ; chmod +t /var/run/shm ; fi
	# Make sure we have forwarding capabilities
	echo "net.ipv4.ip_forward=1
net.ipv4.conf.all.rp_filter=0
net.ipv4.conf.default.rp_filter=0" >>/etc/sysctl.conf
	sysctl -p
}

fix_spice_base_url () {
	pkgos_inifile set /etc/nova/nova.conf spice html5proxy_base_url http://${DEFROUTE_IP}:6082/spice_auto.html
}

setup_novaapi_db () {
	echo "===> Setting-up nova-api db"
	GENERATED_PASSWORD=$(dd if=/dev/random bs=64 count=1 2>|/dev/null | md5sum | awk '{print $1}')
	mysql --defaults-file=/etc/mysql/debian.cnf -e "CREATE DATABASE novaapi"
	mysql --defaults-file=/etc/mysql/debian.cnf -e "GRANT ALL PRIVILEGES ON novaapi.* TO 'novaapi'@'localhost' IDENTIFIED BY '${GENERATED_PASSWORD}'"
	mysql --defaults-file=/etc/mysql/debian.cnf -e "GRANT ALL PRIVILEGES ON nova.* TO 'nova'@'%' IDENTIFIED BY '${GENERATED_PASSWORD}'"
	pkgos_inifile set /etc/nova/nova.conf api_database connection mysql+pymysql://novaapi:${GENERATED_PASSWORD}@localhost/novaapi
	su nova -c "nova-manage api_db sync"
}

restart_all_nova_and_neutron_daemons () {
	for i in /etc/init.d/nova* ; do $i stop ; done
	for i in /etc/init.d/nova* ; do $i start ; done
	for i in /etc/init.d/neutron* ; do $i stop ; done
	for i in /etc/init.d/neutron* ; do $i start ; done
	sleep 10
}

nova_and_neutron_fixups () {
	setup_local_ip
	#fix_nova_tenant_id_in_neutron
	#fix_nova_and_neutron_admin_pass
	misc_system_fix
	fix_spice_base_url
#	setup_novaapi_db
	restart_all_nova_and_neutron_daemons
}

setup_neutron_networking () {
	echo "Trying to connect to neutron..."
	NUM_RETRY=30
	while ! neutron net-list && [ "${NUM_RETRY}" != 0 ] ; do
		NUM_RETRY=$(( $NUM_RETRY - 1 ))
		echo "Retry left: ${NUM_RETRY}"
		sleep 0.5
	done
	echo "... Yeah \o/"

	# Map the existing physical network in Neutron
	neutron net-create ext-net --router:external --provider:physical_network external --provider:network_type flat
	neutron subnet-create --name ext-subnet \
		--allocation-pool start=${EXT_HOST_MIN},end=${EXT_HOST_MAX} \
		--dns-nameserver 8.8.8.8 \
		--gateway ${DEFROUTE_GW} ext-net ${EXT_NET_CIDR} -- --enable_dhcp=False

	# Create the demo LAN
	LAN_NET=`pkgos_get_id neutron net-create --shared demo-net`
	#LAN_SUBNET=`pkgos_get_id neutron subnet-create demo-net --name demo-subnet ${TENANT_NET_CIDR} -- --dns_nameservers list=true ${DEFROUTE_IP}`
	# Sylvain says this is enough, and I don't need to do what's above:
	LAN_SUBNET=`pkgos_get_id neutron subnet-create --name demo-subnet demo-net ${TENANT_NET_CIDR}`

	# Create the router
	neutron router-create demo-router

	# Attach the router on both sides
	# First attach the router to the demo tenant subnet:
	neutron router-interface-add demo-router demo-subnet

	# Attach the router to the external network by setting it as the gateway:
	neutron router-gateway-set demo-router ext-net

	# Create a single floating IP, just for our tests
	neutron floatingip-create ext-net
	neutron floatingip-create ext-net
	neutron floatingip-create ext-net

	# Allow ping and ssh
	neutron security-group-rule-create --direction ingress --protocol tcp --port_range_min 22 --port_range_max 22 default
	neutron security-group-rule-create --protocol icmp --direction ingress default
}

prompt_for_mgmt_network
find_default_ip
calc_host_min_max
install_and_start_network_init_script
source_openrc_if_present
nova_and_neutron_fixups
setup_neutron_networking
